JAX-RSのリファレンス実装、Jerseyの使い方(2)

前回は基本となるアノテーションを軸に、きわめて単純なRESTサービスを構築する手順を紹介しました。今回はやはりRESTといえばXML/JSONということで、XMLやJSONを返すサービスを構築しましょう。

(前回と言っても、ポストしたのがだいたい1年前の日付だということにたった今気づきました。)

XMLを返す

次のようなリソースクラスを作成します。

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以外にも

  • javax.xml.transform.Source
  • byte[]
  • java.io.InputStream
  • java.io.Reader
  • java.io.File
  • その他のJAXBオブジェクト
などがあります。中でもJAXBオブジェクトを扱えることで、サービスの提供と利用がとても手軽になるのですが、その解説は次の機会に譲ります。

JSONを返す

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でラップして返すことができます。

MediaType(MIMEタイプ)の指定

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);
	}
}

新しいアノテーションが出てきました。

@Produces
MIMEタイプでリソースの種類を示す。

ではそれぞれの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オブジェクトの扱いと、余裕があればクライアント(サービスを利用する側)の実装手順を紹介しようと思います。

コメントを残す