JAX-WSとは
JAX-WSはJavaのサーバサイドフレームワークであり、JavaクラスとAPIの構造をマッピングする機能を持ちます。
クラスやメソッドに対してアノテーションを付加することで、簡単にマッピングすることができます。
例えば、APIサーバがapi/hoge/get
GETメソッドを提供したい場合、下記のように記述することができます。
import java.util.List; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import hoge.fuga.Request; import hoge.fuga.Response; @Path("hoge") @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") public class APIResource { @POST @Path("post") public Response post(Request request) { ... return result; } }
クラス、及びメソッドがAPIの階層構造にマッピングされ、整然と記述することができます。
ボディパラメータ(application/json)を受け取る
以前より、application/json
形式のリクエストボディをサーバが受け取れるようにするため、リクエストパラメータ受け取り用クラスをAPIごとに定義していました。
例えば、上記コードのpost
メソッドの引数となっているRequest
型変数には、JSON形式のリクエストボディをJavaオブジェクトに変換した結果が格納されています。この変数の型となっているRequestクラスは、上記post
メソッドのリクエストボディを受け取るためだけに作られた専用のクラスになります。
Request.java
public class Request { private int id; private int label; private int page; }
このやり方で進めてしまうと、JSONボディパラメータを受け取るAPIメソッド一つ作るたびに、専用のパラメータ受け取り用クラスを作成しなければなりません。
APIごとに類似したレスポンスを返すのであれば共通化・一般化したクラスを定義して使い回せばよいのですが、新たに受け取らなければ行けないパラメータが増えた場合、新たにクラスを定義する必要が出てきます。
対応策
Mapオブジェクトで受け取れました。。。
どうやらJAX-WSでは、ユーザ定義クラスに対するマッピングだけでなく、Mapクラスに対するオブジェクトマッピングも行ってくれるみたいです。
import java.util.List; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import hoge.fuga.Response; @Path("hoge") @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") public class APIResource { @POST @Path("post") public Response post(Map<String, Object> request) { // Map内のパラメータを解体 String name = (String)request.get("name"); String label = (String)request.get("label"); int page = (Integer)request.get("name"); .... return result; } }
ただし、MapのValue型が殆どの場合Objectになってしまうので、型変換が暗黙的になってしまうというデメリットはありますが。。。 ココらへんは、仕様書にきちんと記述するなり、コメントで記述するなりしっかりしておく必要があると思います。
JAX-WSの仕様を把握しきれていなかったというオチでした。。。