前回は基本となるアノテーションを軸に、きわめて単純なRESTサービスを構築する手順を紹介しました。今回はやはりRESTといえばXML/JSONということで、XMLやJSONを返すサービスを構築しましょう。
(前回と言っても、ポストしたのがだいたい1年前の日付だということにたった今気づきました。)
次のようなリソースクラスを作成します。
jerseytest.resources.LocalDocumentResource
package jerseytest.resources; import java.io.IOException; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.SAXException; @Path("/indianTeas") public class LocalDocumentResource { @GET public Document getDocument() { try { File f = new File("/path/to/indianTeas.xml"); Document doc = DocumentBuilderFactory.newInstance() .newDocumentBuilder().parse(f); return doc; } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } return null; } }
少しコード量が増えたもののやっていることは単純で、ローカルにあるXMLファイルをDocumentオブジェクトにして返しているだけです。
ではサービスを参照してみましょう。
$ curl "http://localhost:8080/jerseytest/rest/indianTeas" <?xml version="1.0" encoding="UTF-8" standalone="no"?> <teas> <tea>Assam</tea> <tea>Darjeeling</tea> <tea>Nilgiri</tea> </teas>
ちゃんとインドの紅茶リストが返ってきましたね。
リソースクラスのメソッドがデフォルトで返すことのできる型は、Document以外にも
XMLができたら、次はJSONを返してみたくなるのが人情というものです。
JSONの文字列を自前で作って返すことも勿論出来るのですが、ここはjerseyが用意してくれている機能に頼りましょう。依存ライブラリが多いので(10個以上)ここはmavenを使用することをお勧めします。pom.xmlに以下の記述を追加します。
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>1.4</version> </dependency>
次に、MapをJSONで返すリソースクラスを作成してみます。
jerseytest.resources.JsonResource
package jerseytest.resources; import java.util.HashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import org.codehaus.jettison.json.JSONObject; @Path("/json") public class JsonResource { @GET public JSONObject get() { Map m = new HashMap(); m.put("name", "George"); m.put("age", "35"); m.put("gender", "male"); return new JSONObject(m); } }
HashMapをJSONObjectでラップして返しているだけですね。ではサービスを参照してみましょう。
$ curl "http://localhost:8080/jerseytest/rest/json" {"age":"35","name":"George","gender":"male"}
確かにJSON形式のMapになって返ってきました。
Collectionも同様にJSONArrayでラップして返すことができます。
HTTPでは、”リクエスト側が要求するリソースの種類”と”レスポンス側が実際に返すリソースの種類”を表すためにMIMEタイプの指定が可能です。
要求されたMIMEタイプに基づいてレスポンスの種類を変えるリソースクラスを作成してみましょう。
jerseytest.resources.GeorgeResource
package jerseytest.resources; import java.util.HashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.codehaus.jettison.json.JSONObject; @Path("/george") public class GeorgeResource { @GET @Produces(MediaType.TEXT_PLAIN) public String name() { return "I'm George"; } @GET @Produces(MediaType.APPLICATION_JSON) public JSONObject doc() { Map m = new HashMap(); m.put("name", "George"); m.put("age", "35"); m.put("gender", "male"); return new JSONObject(m); } }
新しいアノテーションが出てきました。
ではそれぞれのMIMEタイプを指定して、サービスを参照してみましょう。
まずは"text/plain"からです。
$ curl -H "Accept: text/plain" "http://localhost:8080/jerseytest/rest/george" I'm George.
次に"application/json"です。
$ curl -H "Accept: application/json" "http://localhost:8080/jerseytest/rest/george" {"age":"35","name":"George","gender":"male"}
うまく行きました。親切なgeorgeサービスは、プレーンテキストを要求した場合は名前だけ、JSONを要求した場合は名前以外にも年齢と性別を教えてくれました。
今回はXMLやJSONを返すサービスを構築する手順を紹介しました。これでかなりRESTっぽくなってきましたね。
次回はJAXBオブジェクトの扱いと、余裕があればクライアント(サービスを利用する側)の実装手順を紹介しようと思います。