JavaEE 7をやってみよう。 JAX-RS その3
その2のつづき。
今度はリクエストにパラメータを持たせたパターン……つまり、POSTでの実装を試してみる。
加えて、リクエストはJSONでレスポンスがXMLのパターンをやってみる。
JSON → JAVA変換も、JAVA → XML変換もJAXBという機能を使って行うが、
ランタイムが勝手にやってくれるので、ここでは難しく構える必要はない。
とはいっても、Javaのコードを書く前に
レスポンスのXMLがどんな構造をもつのか位は決める必要があるので、
簡単に下のようなものを考えてみた。
<result> <warShipList> <warShip> <type>軽巡洋艦</type> <name>球磨</name> </warShip> <warShip> <type>軽巡洋艦</type> <name>多摩</name> </warShip> </warShipList> </result>
warShipListにwarShipの情報が0個〜n個で入っている。
warShipにはtypeとnameの要素を持つ、そんな感じ。
これを踏まえて、まず、Beanクラスを作る。
- WarShipクラス
- typeとnameを持つ艦艇クラス。
@XmlType(propOrder={"type", "name"})は、XML出力する際のタグの出力順を表す。
このアノテーションは無くてもXML出力はできるが、
項目名のアルファベット順になってしまうのが嫌なので(型 → 名前の順でしょう、やはり)、追加した。
@XmlElementは重要なアノテーションでこれを付けた項目がXMLの要素として出力される。
メンバに付けるとわかりやすいのだが、メンバはprivateなのでこの例では付けられない。
その代わりアクセサメソッドのgetterにアノテーションを付けている。
package jaxrs.bean; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlType; @XmlType(propOrder={"type", "name"}) public class WarShip { private String type; private String name; /** * typeを取得します。 * @return type */ @XmlElement public String getType() { return type; } /** * typeを設定します。 * @param type type */ public void setType(String type) { this.type = type; } /** * nameを取得します。 * @return name */ @XmlElement public String getName() { return name; } /** * nameを設定します。 * @param name name */ public void setName(String name) { this.name = name; } }
- Catalogクラス
- XMLのタグ名がResultだったけど、Resultクラスとするのもアレなので、カタログということにした。
@XmlRootElementアノテーションが重要で、このアノテーションを持つクラスがJavaクラスからXMLへ変換できる。
名称の通り、このクラスがルートタグとなる。
@XmlRootElementアノテーションのパラメータ"name"があるが、これはルートタグの名称を指定する意味がある。
省略は可能で、省略するとクラス名がタグ名となる。
package jaxrs.bean; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="result") public class Catalog { List<WarShip> shipList; @XmlElement public List<WarShip> getShipList() { return shipList; } public void setShipList(List<WarShip> shipList) { this.shipList = shipList; } }
これでアウトプットは揃ったので、処理をリソースクラスに追加する。
- リソースクラス
- まず、メソッドに@POSTアノテーションを付けてPOST送信された場合に動作するように宣言した。
@Consumesアノテーションで受け入れ可能なパラメータのコンテントタイプを指定している。
リクエストデータはJSONとしたので、"application/json"となっている。
@Producesは前回書いたようにレスポンスのコンテントタイプ。
XMLで返したいので"application/xml"。
@FormattedアノテーションはJBOSS(Wildfly)でしか使えないアノテーションなのだが、これを付けるとXMLの行端に改行が付加されて見やすい形で返されるので付けてみた。
メソッドの戻り値に@XmlRootElementが付いているクラスを使うことで自動的にJava → XML変換が行われる。
インプットについても同じ理屈でJSON → Java変換が行われる。
ただし、こちらはJSONなので@XmlRootElementなどのアノテーションは不要。
構造が合っていれば変換してもらえる。
package jaxrs; import java.util.ArrayList; import java.util.List; import javax.enterprise.context.RequestScoped; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import jaxrs.bean.Catalog; import jaxrs.bean.WarShip; import jaxrs.bean.WarShipList; import org.apache.commons.lang.StringUtils; import org.jboss.resteasy.annotations.providers.jaxb.Formatted; @RequestScoped @Path("ship") public class ShipResource { 〜〜 前回追加分は省略 〜〜 @POST @Consumes({"application/json;charset=UTF-8"}) @Produces({"application/xml;charset=UTF-8"}) @Path("/list") @Formatted public Catalog getShipListJson(WarShip args) { Catalog cat = new Catalog(); List<WarShip> shipList = new ArrayList<WarShip>(); if (StringUtils.equals("D", args.getType())) { shipList.add(getWarShip("駆逐艦", "睦月")); shipList.add(getWarShip("駆逐艦", "如月")); shipList.add(getWarShip("駆逐艦", "皐月")); shipList.add(getWarShip("駆逐艦", "文月")); shipList.add(getWarShip("駆逐艦", "三日月")); } else { shipList.add(getWarShip("軽巡洋艦", "球磨")); shipList.add(getWarShip("軽巡洋艦", "多摩")); shipList.add(getWarShip("軽巡洋艦", "北上")); shipList.add(getWarShip("軽巡洋艦", "大井")); shipList.add(getWarShip("軽巡洋艦", "木曽")); } cat.setShipList(shipList); return cat; } private WarShip getWarShip(String type, String name) { WarShip ship = new WarShip(); ship.setName(name); ship.setType(type); return ship; } }
今回、簡単にテスト実行するためにJMeterを使ってみた。
URLは「http://localhost:8080/アプリケーション名/rest/ship/list」。
リクエストパラメータにtype = "D"をJSONで送ることにする。
そのため、Post Bodyはもちろんのこと、
Httpヘッダにも「content-type: appliction/json」を指定する。
サーバーを起動して実行してみるとなんぞや、XMLは出力されているが形が想定通りに出ていない。
warShipのタグがなく、warShipListのタグがそのまま複数個出力されてしまった。
なんだろう、これ。
といったところで、その4へつづく。