前回は基本となるアノテーションを軸に、きわめて単純な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オブジェクトの扱いと、余裕があればクライアント(サービスを利用する側)の実装手順を紹介しようと思います。