BeanParamをネストさせる

【エントリ変更履歴】

  1. Jerseyのバージョンを1.19 => 2.21 に変更

【前提条件】

[環境]

【概要】

BeanParamアノテーションをネストさせて使う方法です。

結論から先に行くとアノテーションつけるだけ。
今回のやり方をやるのであれば、
JSONで渡したほうが使いやすいかなというところです。

もっと良いやり方がある可能性はありますが。

【設定周り】

pom.xmlとApplicationクラスです。
この辺は基本的な設定しかしていないので読み飛ばして問題ないです。

実際に動かしてみたい人はコピーすれば動くと思います。

[pom.xml]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jp.glory</groupId>
    <artifactId>JAX-RS</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JAX-RS</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.21</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>7.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
[Applicationクラス]
package jp.glory.jax.rs.applicaion;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("service")
public class ApplicationSetting extends Application {
}

【ネストさせる】

親となるRootParamBeanと子となるChildParamBeanの二つを作成します。

[RootParamBean]

package jp.glory.jax.rs.applicaion.resource.beanparam.nest;

import javax.ws.rs.BeanParam;
import javax.ws.rs.FormParam;

public class RootParamBean {

    @FormParam("name")
    private String name = null;

    @FormParam("age")
    private Integer age = null;

    @BeanParam
    private ChildParamBean child = null;

    // アクセサは省略
}

ネストさせたいBeanにBeanParamアノテーションをつけるだけです。

[ChildParamBean]
package jp.glory.jax.rs.applicaion.resource.beanparam.nest;

import javax.ws.rs.FormParam;

public class ChildParamBean {

    @FormParam("skill.name")
    private String name = null;

    @FormParam("skill.year")
    private Integer year = null;

    public String getName() {
        return name;
    }

    // アクセサは省略
}

子側のBeanでは通常どおりにFormParamアノテーションを使っているのですが、
その中のvalue値は注意が必要です。

RootParamBeanの変数名childと
Child ParamBeanのFormParamアノテーションでつけた名前を
組み合わせてくれると 思っていたのですがそうではないみたいです。
(今回の例では”child" + “.” + FormParamアノテーションvalue値を期待していました)

どうやら完全に一致させていないと値が設定されないようです。

この辺は調べ切れていないところもあり、実は簡単にできるというのはあるかもしれないです。

【リソースクラスと画面】

リソースクラスでは受け取ったBeanの中身をコンソールに出力します。

[リソースクラス]
package jp.glory.jax.rs.applicaion.resource.beanparam.nest;

import javax.ws.rs.BeanParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("/beanparam/nest")
public class NestParam {

    @POST
    public Response send(@BeanParam RootParamBean param) {

        System.out.println("param.name : " + param.getName());
        System.out.println("param.age : " + param.getAge());

        System.out.println("param.skill.name : " + param.getChild().getName());
        System.out.println("param.skill.year : " + param.getChild().getYear());

        return Response.ok().build();
    }
}
[画面]

画面はFormParamアノテーションで指定した値と同じ入力フォームがあるだけです。

<!DOCTYPE html>
<html>
    <head>
        <title>BeanParamのネスト</title>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    </head>
    <body>
        <form action="/JAX-RS/service/beanparam/nest" method="post">
            <dl>
                <dt>名前</dt>
                <dd>
                    <input type="text" name="name" value="シュンツ" />
                </dd>
                <dt>年齢</dt>
                <dd>
                        <input type="text" name="age" value="28" />
                </dd>
                <dt>スキル</dt>
                <dd>
                    <dl>
                        <dt><input type="text" name="skill.name" value="Java" /></dt>
                        <dd><input type="text" name="skill.year" value="10" /></dd>
                    </dl>
                </dd>
            </dl>
            <button>送信</button>
        </form>
    </body>
</html>

【実行結果】

情報:   param.name : シュンツ
情報:   param.age : 28
情報:   param.skill.name : Java
情報:   param.skill.year : 10

ということでネストさせたパラメータも受け取れています。

【動いたけど・・・】

以下の二点によりちょっとこのやり方はやらないほうがいいかなぁと。

  1. パラメータの名前が固定化される
  2. リストとしては受け取れない
[パラメータの名前が固定化される]

ChildParamBean内でパラメータ名が固定化はされるのは当然なのですが、
ChildParamBean自体のパラメータ名が固定化されるのは微妙かなと。

今回はskillという変数名で固定化されています。
場所によってはBean自体の名前は変えたいというときにこのやり方だと対応できないです。

[リストとしては受け取れない]

概要の通りで複数件受け取れないのは問題です。
ネストさせたBeanを使うときはコンポーネント化された部品を使っているか繰り返しだと思うので、
使いときに子のやり方では使えないです。

他に良いやり方があれば良いのですが、思いつかないですね。


JAX-RSでパラメータの受け取りをするときはJSONで行う。
くらいに割り切ったほうがいいのかなと個人的には思います。