JAX-RS(Jersey)を使ってみる

JaveEE6に対応しているGlassfish 3.0を使う方が手っ取り早いとは思いますが、、サーブレットコンテナとしてTomcat6.0を使った環境でJAX-RSを使ってみます。
JAX-RSの実装としては、JavaによるRESTfulシステム構築では、Jersey, Apache CXF, JBoss RESTEasyなんかが紹介されています。CXFはJAX-WSも含んでいて大きそうなので、今回は参照実装であるJersey 1.5を使ってみます。前提としてMavenを使ったWebアプリケーションのプロジェクトがあるとします。

pom.xmlでの依存ライブラリの追加

pom.xmlにrepositoryとdepenencyを追加します。jersey-jsonはJSONを使用する場合に追加します。Jacksonが使われるようです。

	<repositories>
		<!-- 省略 -->
		<repository>
		    <id>maven2-repository.dev.java.net</id>
		    <name>Java.net Repository for Maven</name>
		    <url>http://download.java.net/maven/2/</url>
		    <layout>default</layout>
		</repository>
	</repositories>
	<dependencies>
		<!-- 省略 -->
		<dependency>
		    <groupId>com.sun.jersey</groupId>
		    <artifactId>jersey-server</artifactId>
		    <version>1.5</version>
		</dependency>
		<dependency>
		    <groupId>com.sun.jersey</groupId>
		    <artifactId>jersey-json</artifactId>
		    <version>1.5</version>
		</dependency>
	<dependencies>

リソースの作成

とりあえず簡単なリソースクラスを作成します。/helloというパスにGETメソッドでアクセスすると"Hello World"というテキストを返します。

package com.azuki3.sample.jaxrs.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class HelloWorldResource {

	@GET
	@Produces(MediaType.TEXT_PLAIN)
	public String sayHello(){
		return "Hello World";
	}
}

Applicationクラスの作成

ディプロイ対象となるリソースを記述したApplicationクラスを作成します。

package com.azuki3.sample.jaxrs.config;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import com.azuki3.sample.jaxrs.resources.HelloWorldResource;

public class MyApplication extends Application {
	@Override
	public Set<Class<?>> getClasses() {
		Set<Class<?>> s = new HashSet<Class<?>>();
		s.add(HelloWorldResource.class);
		return s;
	}
}

web.xmlへのサーブレットの追加

この辺はJaveEE6対応のコンテナだと不要ですが、今回は、JaveEE6/JAX-RSに未対応のTomcat6.0なので、web.xmlサーブレットの記述を追加します。

	<servlet>
		<servlet-name>Jersey REST Service</servlet-name>
		<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
		<init-param>
			<param-name>javax.ws.rs.Application</param-name>
			<param-value>com.azuki3.sample.jaxrs.config.MyApplication</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Jersey REST Service</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>

JerseyはデフォルトではScanningResourceConfigというクラスがリソースをスキャンして登録してくれるようです。そのためApplicationクラスを登録しなくてもリソースにアクセスできます。

または、リソースの存在するパッケージを指定することも可能で、その場合にはinit-paramで以下のようにパッケージを指定します。

<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.azuki3.sample.jaxrs.resources</param-value>

リソースにアクセスする

Tomcatを起動してブラウザから、http://localhost:8080/jaxrs/rest/hello にアクセスすると*1、"Hello World"と表示されます。

JSONを使用する

レスポンスをJSON形式にしてみます。リソースとして連絡先を表すContactというクラスを作成します。@XmlRootElementアノテーションを付けておきます。

package com.azuki3.sample.jaxrs.entity;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Contact {
	private Integer id;
	private String name;
	private String address;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
}

このリソースにアクセスするためのContactResourceクラスを作成します。@Producesアノテーションで。MediaType.APPLICATION_JSONを指定します。

package com.azuki3.sample.jaxrs.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.azuki3.sample.jaxrs.entity.Contact;
import com.azuki3.sample.jaxrs.service.AbstractService;
import com.sun.jersey.api.NotFoundException;

@Path("/contacts")
public class ContactResources{

	private static Contact[] contacts = {
			createContact(1, "foo", "Tokyo"),
			createContact(2, "bar", "Osaka"),
			createContact(3, "baz", "Naogya")
	};


	@GET
	@Produces({MediaType.APPLICATION_JSON})
	public Contact[] getContacts() {
		return contacts;
	}

	@Path("{id}")
	@GET
	@Produces({MediaType.APPLICATION_JSON})
	public Contact getContact(@PathParam("id")Integer id) {
		if(id > contacts.length){
			throw new NotFoundException("No such Contact.");
		}
		return  contacts[id-1];
	}

	private static Contact createContact(Integer id, String name, String address){
		Contact contact = new Contact();
		contact.setId(id);
		contact.setName(name);
		contact.setAddress(address);
		return contact;
	}
}

getContactで指定されたidのContactが存在しない場合に、nullを返すとステータスが204(No content)になり、リソースは存在するが内容がないということになってしまうので、404を返すためにNotFoundExceptionをスローしています。ちなみにidに整数以外を指定した場合も404になります(idの型が違うのでContactResource自体が呼び出されません)。

MyApplicationクラスにContactResourcesを追加します。
これで、http://localhost:8080/jaxrs/rest/contacts にアクセスすると以下のようにすべてのContactがJSONで返されます。

{"contact":[{"address":"Tokyo","id":"1","name":"foo"},{"address":"Osaka","id":"2","name":"bar"},{"address":"Naogya","id":"3","name":"baz"}]}

http://localhost:8080/jaxrs/rest/contacts/1 にアクセスすると以下のようにid=1のContactがJSONで返されます。

{"address":"Tokyo","id":"1","name":"foo"}

まとめ

今回はさわり程度で、、DBへのアクセスやリソースの追加・更新を行っていないので非常に簡単でした。
次はSeasar2との連携させてS2JDBCでDBにアクセスする方法などを試してみたいと思います。

参考

以下のサイトを参考にしました。

JavaによるRESTfulシステム構築

JavaによるRESTfulシステム構築


RESTful Webサービス

RESTful Webサービス

*1:"jaxrs"はコンテキストパスです。