The Java EE 7 Tutorialの29 Building RESTful Web Services with JAX-RSの章をテキトーに訳した。
29 Building RESTful Web Services with JAX-RS
この章では、RESTアーキテクチャ・RESTfule webサービス・Java API for RESTful Web Services (JAX-RS、JSR 339で定義)、を解説します。
JAX-RSにより、開発者はJava言語を使用してRESTfule webサービスを簡単に作成できます。
この章では以下のトピックを扱います。
- What Are RESTful Web Services?
- Creating a RESTful Root Resource Class
- Example Applications for JAX-RS
- Further Information about JAX-RS
29.1 What Are RESTful Web Services?
RESTful webサービス(RESTful web services)は、疎結合で軽量なwebサービスで、インターネット経由のクライアント用にAPIを作成するのにとりわけ適しています。Representational State Transfer (REST)はクライアントサーバアプリケーションのアーキテクチャスタイルの一つで、リクエストとレスポンスを通してリソース(resources)の表現(representations)を交換(transfer)することが中心となっている概念です。RESTアーキテクチャスタイルでは、データと機能はリソースとみなされ、また、一般的にはWebのリンクであるUniform Resource Identifiers (URIs)を使用してアクセスします。リソースはドキュメントによって表現され、単純で明確に定義された操作の組み合わせによって変更されます。
たとえば、RESTリソースには都市の現在の天候状況が考えられます。このリソースの表現になりうるのは、XMLドキュメント・画像ファイル・HTMLページ、などです。クライアントは特定の表現を取得したり、データ更新によってリソースを修正したり、リソースを完全に削除できたりします。
RESTアーキテクチャスタイルは、HTTPのような、ステートレスな通信プロトコルを使用するように設計されています。RESTアーキテクチャスタイルでは、クライアントとサーバは標準化されたインタフェースとプロトコルを使用してリソース表現を交換します。
以下の原則がRESTfulアプリケーションをシンプルで軽量で高速になるように促します。
- Resource identification through URI: RESTful webサービスはクライアントとの通信ターゲットを一意に特定するためのリソースセットを公開します。URIによってリソースは一意に指定され、リソースとサービスディスカバリ用のグローバルなアドレス空間を提供します。詳細な情報についてはThe @Path Annotation and URI Path Templatesを参照してください。
- Uniform interface: リソースは4つの操作、生成(create)・読み込み(read)・更新(update)・削除(delete)に固定されており、PUT, GET, POST, DELETEに相当します。PUTは新しいリソースを生成、そのリソースはDELETEで削除可能です。GETは表現におけるリソースの現在の状態を取得します。POSTはリソースの新しい状態を転送します。詳細な情報についてはResponding to HTTP Methods and Requestsを参照してください。
- Self-descriptive messages: リソースと表現は切り離されており、その理由はコンテンツは様々なフォーマットでアクセスされるためで、たとえば、HTML, XML, プレーンテキスト, PDF, JPEG, JSONまたはその他のドキュメントフォーマットなどです。リソースに関するメタデータが利用可能で、キャッシュコントロール・通信エラーの検出・適切な表現フォーマットのネゴシエート・認証やアクセス制御の実行、に使用されます。詳細な情報についてはResponding to HTTP Methods and RequestsとUsing Entity Providers to Map HTTP Response and Request Entity Bodiesを参照してください。
- Stateful interactions through links: リソースとのすべての通信はステートレスで、リクエストメッセージは自己完結しています。ステートフルな通信は明示的な状態転送のコンセプトに基づいています。状態をやり取りするための技術としては、URIリライティング、Cookie、hiddenフィールドなどがあります。状態は、以降の通信の状態を検証するために、レスポンスメッセージに埋め込みが可能です。詳細な情報については、Using Entity Providers to Map HTTP Response and Request Entity BodiesとJAX-RS Overviewの"Building URIs"を参照してください。
29.2 Creating a RESTful Root Resource Class
Root resource classesは、@Path
アノテーションを持つ"plain old Java objects" (POJOs)か、少なくとも一つの@Path
アノテーションが付与されたメソッドを持つクラス
Resource methodsは、request method designatorアノテーションを付与されたリソースクラスのメソッドです。このセクションではRESTful webサービスを作成するためにJavaクラスに付与するアノテーションの使用方法について説明します。
29.2.1 Developing RESTful Web Services with JAX-RS
JAX-RSは、RESTアーキテクチャを使用するアプリケーションをJavaプログラミング言語のAPIを使用して簡単に作成できるように設計されたものです。
JAX-RS APIはRESTful webサービスの開発をシンプルにするためにJavaプログラミング言語のアノテーションを使用します。開発者はリソースと実行するアクションを定義するのにJAX-RSアノテーションをJavaプログラミング言語のクラスファイルに付与します。JAX-RSアノテーションはランタイムアノテーションです。それゆえに、ランタイムのリフレクションはヘルパークラスとリソースのアーティファクトを生成します。JAX-RSリソースクラスが含まれるJava EEアプリケーションアーカイブは、設定済みリソース、ヘルパークラスと生成されたアーティファクトを持ち、Java EEサーバにアーカイブをデプロイすることでクライアントにリソースを公開します。
表 29-1はJAX-RSが定義するアノテーションと使用方法の要約のリストです。JAX-RS APIの詳細な情報については http://docs.oracle.com/javaee/7/api/ を参照してください。
アノテーション | 概要 |
---|---|
@Path |
@Path の値にはこのJavaクラスがホストする相対URIパスを指定します。たとえば/helloworld 。また、URIパステンプレートでURIに組み込み変数を使用可能です。たとえば、ユーザ名をURIの変数としてアプリケーションに渡すことが出来ます。/helloworld/{username} |
@GET |
@GET はrequest method designatorで同名のHTTPメソッドに相当します。このrequest method designatorのアノテーションが付与されたJavaのメソッドはHTTP GETリクエストを処理します。リソースの振る舞いは、リソースが応答するためのHTTPメソッドによって決定されます。 |
@POST |
@POST はrequest method designatorで同名のHTTPメソッドに相当します。このrequest method designatorのアノテーションが付与されたJavaのメソッドはHTTP POSTリクエストを処理します。リソースの振る舞いは、リソースが応答するためのHTTPメソッドによって決定されます。 |
@PUT |
@PUT はrequest method designatorで同名のHTTPメソッドに相当します。このrequest method designatorのアノテーションが付与されたJavaのメソッドはHTTP PUTリクエストを処理します。リソースの振る舞いは、リソースが応答するためのHTTPメソッドによって決定されます。 |
@DELETE |
@DELETE はrequest method designatorで同名のHTTPメソッドに相当します。このrequest method designatorのアノテーションが付与されたJavaのメソッドはHTTP DELETEリクエストを処理します。リソースの振る舞いは、リソースが応答するためのHTTPメソッドによって決定されます。 |
@HEAD |
@HEAD はrequest method designatorで同名のHTTPメソッドに相当します。このrequest method designatorのアノテーションが付与されたJavaのメソッドはHTTP HEADリクエストを処理します。リソースの振る舞いは、リソースが応答するためのHTTPメソッドによって決定されます。 |
@PathParam |
@PathParam はリソースクラスでパラメータを抽出するために使用するアノテーションです。URIパスのパラメータをリクエストURIから抽出し、パラメータ名が@Path クラスレベルアノテーションで指定されているURIパステンプレート変数名に対応します。 |
@QueryParam |
@QueryParam はリソースクラスでパラメータを抽出するために使用するアノテーションです。クエリパラメータはリクエストURIクエリパラメータから抽出します。 |
@Consumes |
@Consumes はクライアントが送信するもののうちリソースが受け入れ可能な表現のMIMEタイプを指定するために使用します。 |
@Produces |
@Produces はクライアントへの返信とリソースが生成可能な表現のMIMEタイプを指定するために使用します。例としてはtext/plain 。 |
@Provider |
@Provider はMessageBodyReader とMessageBodyWriter などをJAX-RSランタイムに設定するために使用します。HTTPリクエストでは、MessageBodyReader はHTTPリクエストのエンティティボディをメソッドパラメータにマップするために使用します。対してレスポンスでは、MessageBodyWriter を使用して戻り値をHTTPレスポンスのエンティティボディにマップします。アプリケーションが、HTTPヘッダーや異なるステータスコードなどの追加のメタデータの提供が必要な場合、Response.ResponseBuilder を使用して構築可能な、エンティティをラップするResponse を戻り値に取ることが出来ます。 |
@ApplicationPath |
@ApplicationPath はアプリケーションのURLマッピングを定義するために使用します。@ApplicationPath で指定するパスはベースURIで、リソースクラスの@Path アノテーションで指定されるすべてのリソースURIのベースとなります。@ApplicationPath はjavax.ws.rs.core.Application のサブクラスにのみ適用可能です。 |
29.2.2 Overview of a JAX-RS Application
以下のコードはJAX-RSアノテーションを使用するルートリソースクラスのごく単純な例です。
package javaeetutorial.hello; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.UriInfo; /** * ルートリソース ("helloworld"パスで公開される) */ @Path("helloworld") public class HelloWorld { @Context private UriInfo context; /** HelloWorldのインスタンスを作成する。 */ public HelloWorld() { } /** * helloWorld.HelloWorldインスタンスの表現を取得する。 * @return java.lang.Stringのインスタンス */ @GET @Produces("text/html") public String getHtml() { return "<html lang=\"en\"><body><h1>Hello, World!!</h1></body></html>"; } }
以降のセクションでこのサンプルで使われているアノテーションについて説明します。
@Path
の値は相対URIのパスです。この例では、JavaクラスはURIパス/helloworld
にホストされます。これは最も単純な@Path
の使用法で、静的なURIパスを使用しています。変数をURIに埋め込み可能で、URIパステンプレート(URI path templates)のURIにはシンタックス内に変数を埋め込み可能です。@GET
は、JAX-RSが定義する@POST
,@PUT
,@DELETE
,@HEAD
と同様なrequest method designatorで、同名のHTTPメソッドに相当します。この例では、アノテーションが付与されたJavaのメソッドはHTTP GETリクエストを処理します。リソースの振る舞いは、リソースがレスポンスを行うHTTPメソッドによって決定されます。@Produces
はクライアントに送り返すためにリソースが生成可能なMIMEメディアタイプを指定するために使用します。この例では、JavaメソッドはMIMEメディアタイプ"text/html"
で指定される表現を生成します。@Consumes
はクライアントが送信してリソースが受け入れ可能なMIMEメディアタイプを指定するために使用します。上記の例を修正してgetHtml
メソッドが返すメッセージを格納するよう、以下のように修正可能です。
@POST @Consumes("text/plain") public void postHtml(String message) { // Store the message }
29.2.3 The @Path Annotation and URI Path Templates
@Path
にはリソースが応答するためのURIパステンプレートを指定し、また、リソースのクラスもしくはメソッドレベルに付与します。@Path
の値は、URIパステンプレートです。また、リソースがデプロイされるサーバのベースURIと、JAX-RSランタイムがレスポンスを返すためのURLパターンと、アプリケーションのコンテキストルートに対し、相対的です。
URIパステンプレートはURIシンタックス内に埋め込まれる変数付きのURIです。これらの変数は、置換されるURLに基づいてリソースがリクエストに応答するためにランタイムが置換します。変数は中括弧({
と}
)で指定します。以下は@Path
の例です。
@Path("/users/{username}")
この例では、ユーザは彼or彼女の名前をタイプし、それからこのURIパステンプレートへのリクエストに応答できるように設定されたJAX-RS webサービスがレスポンスを返します。ユーザがユーザ名`Galileo"とタイプしたら、webサービスは以下のURLにレスポンスを返します。
http://example.com/users/Galileo
ユーザ名を取得するには、以下のようにリクエストメソッドのパラメータに@PathParam
を使用します。
@Path("/users/{username}") public class UserResource { @GET @Produces("text/xml") public String getUser(@PathParam("username") String userName) { ... } }
デフォルトでは、URL変数は正規表現"[^/]+?"
にマッチします。この変数は、変数名の後ろに異なる正規表現を指定することでカスタマイズが可能です。たとえば、ユーザ名を小文字と大文字数字のみで構成したい場合、変数定義のデフォルトの正規表現をオーバーライドします。
@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
この例では、username
変数は、一文字目が大文字か小文字で始まり、二文字目以降がゼロか英数字とアンダースコアで始まる場合のみマッチします。ユーザ名がテンプレートにマッチしない場合、クライアントには404 (Not Found)レスポンスが返されます。
@Path
は、スラッシュ(/)を先頭や末尾に持つ必要はありません。JAX-RSランタイムは、先頭や末尾にスラッシュを持つかどうかに関わらず、同じ結果になるようにURIパステンプレートをパースします。
URIパステンプレートは一つ以上の変数を持ち、各変数は中括弧で囲みます。変数名は{
で始めて}
で終わります。先の例では、username
が変数名です。URIパステンプレートにレスポンスを返すよう設定されたリソースは、URI中の{username}
に対応するURIデータをusername
変数として、ランタイムが処理します。
たとえば、URIパステンプレートhttp://example.com/myContextRoot/resources/{name1}/{name2}/
に相当するリソースをデプロイしたいとすると、まずhttp://example.com/myContextRoot
URIでリクエストとレスポンスが可能なアプリケーションをJava EEサーバーにデプロイし、リソースに以下の@Path
アノテーションを付与します。
@Path("/{name1}/{name2}/") public class SomeResource { ... }
この例では、JAX-RSヘルバーサーブレット用のURLパターンを、web.xml
で指定します。
<servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping>
変数中の文字がURLの予約語と衝突する場合、その文字はパーセントでエンコードされたもので置換されます。たとえば、変数のスペースは%20
に置換されます。
URLパステンプレートを定義するとき、置換後のURLが有効になるように注意してください。
表 29-2は、URIパステンプレートの例と、どのようにURLが置換後に解決されるか、の例を示しています。以下の変数名と値が例で使用されます。
name1
:james
name2
:gatz
name3
:location
:Main%20Street
question
:why
Note: name3
の値は空文字です。
表 29-2 URIパステンプレートの例
URIパステンプレート | 置換後のURI |
---|---|
http://example.com/{name1}/{name2}/ |
http://example.com/james/gatz/ |
http://example.com/{question}/{question}/{question}/ |
http://example.com/why/why/why/ |
http://example.com/maps/{location} |
http://example.com/maps/Main%20Street |
http://example.com/{name3}/home/ |
http://example.com//home/ |
29.2.4 Responding to HTTP Methods and Requests
リソースの振る舞いはHTTPメソッド(一般的には、GET, POST, PUT, DELETE)が決定します。
29.2.4.1 The Request Method Designator Annotations
Request method designatorアノテーションは、JAX-RSが定義するランタイムアノテーションで、同名のHTTPメソッドに相当します。リソースクラスファイル内では、HTTPメソッドはrequest method designatorを付与されたJavaのメソッドにマップされます。リソースの振る舞いは、リソースがレスポンスを返すHTTPメソッドによって決定されます。JAX-RSは一般的なHTTPメソッドであるGET, POST, PUT, DELETE, HEADのrequest method designatorsを定義しています。また、自前のカスタムrequest method designatorsを作ることも出来ますが、そのカスタマイズについては本ドキュメントの対象外です。
以下の例はPUTメソッドを使用するストレージコンテナの作成もしくは更新を示しています。
@PUT public Response putContainer() { System.out.println("PUT CONTAINER " + container); URI uri = uriInfo.getAbsolutePath(); Container c = new Container(container, uri.toString()); Response r; if (!MemoryStore.MS.hasContainer(c)) { r = Response.created(uri).build(); } else { r = Response.noContent().build(); } MemoryStore.MS.createContainer(c); return r; }
デフォルトでは、もし明示的にHEADとOPTIONSが実装されていない場合、JAX-RSランタイムは自動的にそれらのメソッドをサポートします。HEADは、ランタイムは実装済みのGETメソッドが存在すればそれを呼び出し、レスポンスエンティティが設定されていたらそれを無視します。OPTIONは、リソースがサポートするHTTPメソッドの組み合わせをAllow
レスポンスヘッダーに設定します。また、JAX-RSランタイムはリソースを記述するWeb Application Definition Language (WADL)を返します。これの詳細については http://www.w3.org/Submission/wadl/ を参照してください。
request method designatorsアノテーションを付与したメソッドの戻り値は、void
かjavax.ws.rs.core.Response
でなければなりません。Extracting Request Parametersで解説したように、複数のパラメータを@PathParam
や@QueryParam
アノテーションを使用してURIから抽出できます。Javaの型とエンティティボディ間の変換は、MessageBodyReader
やMessageBodyWriter
などの、エンティティプロバイダーの責任です。レスポンスに追加のメタデータが必要なメソッドはResponse
クラスのインスタンスを戻り値にします。ResponseBuilder
クラスはBuilderパターンを使用してReponse
インスタンスを生成する方法を提供します。HTTP PUTとPOSTメソッドはHTTPリクエストボディを持つので、PUTとPOSTリクエストに応答するためにメソッドではMessageBodyReader
を使用します。
@PUT
と@POST
はリソースの作成や更新に使用可能です。POSTは多様な意味を持つため、POSTのセマンティクス定義はアプリケーション次第になります。PUTは明確に定義されたセマンティクスを持ちます。生成にPUTを使用するとき、クライアントは新規に生成されたリソースのURIを宣言します。
PUTは作成もしくは更新されたリソースの明確なセマンティクスを持ちます。クライアントが送信する表現は、同一のメディアタイプのGETを使用して受信する表現と同一でなければなりません。PUTメソッドの良くある間違いとしては、PUTはリソースの部分的な更新を許可しません。POSTでリソースを作成する一般的なアプリケーションパターンは、ロケーションヘッダーのレスポンスに201
を返し、新規作成されたリソースのURLを値として持ちます。このパターンでは、webサービスは新規作成されたリソースのURIを宣言します。
29.2.4.2 Using Entity Providers to Map HTTP Response and Request Entity Bodies
エンティティプロバイダー(Entity providers)は表現とJavaの型とのマッピングを行います。エンティティプロバイダーにはMessageBodyReader
とMessageBodyWriter
の二種類があります。HTTPリクエストでは、MessageBodyReader
がHTTPリクエストエンティティボディとメソッドパラメータのマッピングに使われます。一方、MessageBodyWriter
を使用して戻り値はHTTPレスポンスエンティティボディにマッピングされます。もしアプリケーションがHTTPヘッダーや異なるステータスコードなどの追加のメタデータを提供する場合、エンティティをラップするResponse
を返すことが可能で、Response
はResponse.ResponseBuilder
を使用して作成します。
表 29-3はHTTPリクエストとレスポンスエンティテイボディで自動的にサポートされる標準タイプを示しています。エンティティプロバイダーは以下の標準タイプを使用できない場合のみ作成する必要があります。
表 29-3 HTTPリクエストとレスポンスエンティテイボディでサポートされる型
Java Type | Supported Media Types |
---|---|
byte[] |
すべてのメディアタイプ (*/* ) |
java.lang.String |
すべてのテキストメディアタイプ (text/* ) |
java.io.InputStream |
すべてのメディアタイプ (*/* ) |
java.io.Reader |
すべてのメディアタイプ (*/* ) |
java.io.File |
すべてのメディアタイプ (*/* ) |
javax.activation.DataSource |
すべてのメディアタイプ (*/* ) |
javax.xml.transform.Source |
XMLメディアタイプ (text/xml , application/xml , application/*+xml ) |
javax.xml.bind.JAXBElement とアプリケーションが提供するJAXBクラス |
XMLメディアタイプ (text/xml , application/xml , application/*+xml ) |
MultivaluedMap<String, String> |
フォームコンテンツ (application/x-www-form-urlencoded ) |
StreamingOutput |
すべてのメディアタイプ (/), MessageBodyWriter のみ |
以下の例は@Consumes
と@Provider
アノテーションでMessageBodyReader
を使用する方法を示しています。
@Consumes("application/x-www-form-urlencoded") @Provider public class FormReader implements MessageBodyReader<NameValuePair> {
以下の例は@Produces
と@Provider
アノテーションでMessageBodyWriter
を使用する方法を示しています。
@Produces("text/html") @Provider public class FormWriter implements MessageBodyWriter<Hashtable<String, String>> {
以下の例はResponseBuilder
の使用方法を示しています。
@GET public Response getItem() { System.out.println("GET ITEM " + container + " " + item); Item i = MemoryStore.MS.getItem(container, item); if (i == null) throw new NotFoundException("Item not found"); Date lastModified = i.getLastModified().getTime(); EntityTag et = new EntityTag(i.getDigest()); ResponseBuilder rb = request.evaluatePreconditions(lastModified, et); if (rb != null) return rb.build(); byte[] b = MemoryStore.MS.getItemData(container, item); return Response.ok(b, i.getMimeType()). lastModified(lastModified).tag(et).build(); }
29.2.5 Using @Consumes and @Produces to Customize Requests and Responses
リソースへの送信とクライアントに送り返す情報はMIMEメディアタイプとしてHTTPリクエストやレスポンスのヘッダーに指定します。リソースが応答もしくは生成が可能な表現のMIMEメディアタイプを以下のアノテーションで指定可能です。
javax.ws.rs.Consumes
javax.ws.rs.Produces
デフォルトでは、リソースクラスはHTTPリクエストとレスポンスヘッダーで指定される表現のすべてのMIMEメディアタイプを応答もしくは生成が可能です。
29.2.5.1 The @Produces Annotation
@Produces
は、リソースがクライアントに返答および生成することができる表現や、MIMEメディタタイプの指定に使用します。@Produces
がクラスレベルに適用されている場合、リソースのすべてのメソッドは指定されたMIMEタイプをデフォルトで生成可能です。メソッドレベルに適用されている場合、クラスレベルの@Produces
をオーバーライドします。
リソースにクライアントリクエストのMIMEタイプを生成可能なメソッドが存在しない場合、JAX-RSランタイムはHTTP "406 Not Acceptable"エラーを返します。
@Produces
の値はMIMEタイプ文字列の配列か、MediaType
定数値のカンマ区切りリストです。たとえば、
@Produces({"image/jpeg,image/png"})
以下の例はクラスとメソッドレベル両方に@Produces
を適用する方法を示しています。
@Path("/myResource") @Produces("text/plain") public class SomeResource { @GET public String doGetAsPlainText() { ... } @GET @Produces("text/html") public String doGetAsHtml() { ... } }
doGetAsPlainText
メソッドはクラスレベルの@Produces
のデフォルトMIMEタイプになります。doGetAsHtml
メソッドの@Produces
はクラスレベルの@Produces
をオーバーライドして、メソッドはプレーンテキストではなくHTMLを生成すると指定しています。
また、@Produces
はメディタタイプの指定にjavax.ws.rs.core.MediaType
で定義されている定数値を使うことも出来ます。たとえば、MediaType.APPLICATION_XML
の指定は"application/xml"
と指定することと同等です。
@Produces(MediaType.APPLICATION_XML) @GET public Customer getCustomer() { ... }
リソースクラスが一つ以上のMIMEメディタタイプを生成可能な場合、リソースメソッドはクライアントが宣言したメディアタイプに最も適合するものが選択されます。多くの場合、HTTPリクエストのAccept
ヘッダーで宣言しているものが最も適合するものになります。たとえば、Accept
ヘッダーがAccept: text/plain
の場合、doGetAsPlainText
メソッドが実行されます。また、Accept
ヘッダーがAccept: text/plain;q=0.9
, text/html
の場合、クライアントはtext/plain
とtext/html
のメディアタイプを受け入れ可能と宣言していますが、後者を選択するのでdoGetAsHtml
メソッドが実行されます。
@Produces
に一つ以上のメディアタイプを宣言可能です。以下のコード例はその方法を示しています。
@Produces({"application/xml", "application/json"}) public String doGetAsXmlOrJson() { ... }
application/xml
もしくはapplication/json
のどちらかのメディアタイプが受け入れ可能な場合に、doGetAsXmlOrJson
メソッドは実行されます。両方ともが等しく受け入れ可能な場合、先に書かれている方が選択されます。先の例は分かりやすくするために明示的にMIMEメディアタイプを参照しています。タイプミスエラーを減らすには、可能な限り定数値を使用します。定数値の詳細についてはjavax.ws.rs.core.MediaType
のAPIドキュメントを参照してくださ。
29.2.5.2 The @Consumes Annotation
@Consumes
はリソースがクライアントから受け入れ可能な表現のMIMEメディアタイプを指定できます。@Consumes
がクラスレベルに適用されている場合、すべてのレスポンスメソッドは指定されたMIMEタイプをデフォルトで受け入れます。メソッドレベルに適用されている場合、@Consumes
はクラスレベルに適用されている@Consumes
をオーバーライドします。
もしリソースがクライアントリクエストのMIMEタイプを受け入れ不可能な場合、JAX-RSランタイムはHTTP 415 ("Unsupported Media Type")エラーを送り返します。
@Consumes
の値は受け入れ可能なMIMEタイプString
の配列か、MediaType
定数値のカンマ区切りリストです。たとえば、
@Consumes({"text/plain,text/html"})
これは以下と同等です。
@Consumes({MediaType.TEXT_PLAIN,MediaType.TEXT_HTML})
以下の例はクラスとメソッド両方に@Consumes
を適用する方法を示しています。
@Path("/myResource") @Consumes("multipart/related") public class SomeResource { @POST public String doPost(MimeMultipart mimeMultipartData) { ... } @POST @Consumes("application/x-www-form-urlencoded") public String doPost2(FormURLEncodedProperties formData) { ... } }
doPost
メソッドはクラスレベルの@Consumes
のMIMEメディアタイプがデフォルトになります。doPost2
メソッドはクラスレベルの@Consumes
をオーバーライドし、URLエンコードフォームデータを受け入れ可能にしています。
リクエストされたMIMEタイプに応答可能なリソースメソッドが存在しない場合、HTTP 415 ("Unsupported Media Type") エラーがクライアントに返されます。
この章で以前説明したHelloWorld
サンプルは、以下のように、@Consumes
を使用してメッセージを設定可能なように修正できます。
@POST @Consumes("text/html") public void postHtml(String message) { // Store the message }
この例では、Javaのメソッドはtext/plain
*1MIMEメディアタイプの表現を受け入れます。リソースメソッドはvoid
を返す点に注意してください。これは、返される表現は無いことと、HTTP 204 ("No Content")のステータスコードでレスポンスが返されること、を意味します。
29.2.6 Extracting Request Parameters
リクエストメソッドのパラメータにはリクエストから情報を抽出するためにアノテーションを付与することができます。以前の例では、@Path
で宣言したパスにマッチするリクエストURLのパスコンポーネントから、パスパラメータを抽出するために@PathParam
の使用方法を示しました。
リソースクラスでは以下の種類のパラメータを抽出可能です。
クエリパラメータ(Query parameters)は、メソッドのパラメータ引数にjavax.ws.rs.QueryParam
を設定し、リクエストURIのクエリパラメータから抽出するものです。以下のサンプルは@QueryParam
を使用してリクエストURLのQuery
コンポーネントからクエリパラメータを抽出しています。
@Path("smooth") @GET public Response smooth( @DefaultValue("2") @QueryParam("step") int step, @DefaultValue("true") @QueryParam("min-m") boolean hasMin, @DefaultValue("true") @QueryParam("max-m") boolean hasMax, @DefaultValue("true") @QueryParam("last-m") boolean hasLast, @DefaultValue("blue") @QueryParam("min-color") ColorParam minColor, @DefaultValue("green") @QueryParam("max-color") ColorParam maxColor, @DefaultValue("red") @QueryParam("last-color") ColorParam lastColor ) { ... }
クエリパラメータstep
はリクエストURIのクエリコンポーネント上に存在し、step
の値は抽出されると32bit整数としてパースされ、step
メソッド引数に代入されます。もしstep
が存在しない場合、@DefaultValue
で宣言されているデフォルト値の2がstep
メソッド引数に代入されます。step
の値が32bit引数としてパース出来ない場合、HTTP 400 ("Client Error")レスポンスが返されます。
ユーザ定義型をクエリパラメータとして使用可能です。以下のコードは上の例のクエリパラメータで使用されているColorParam
クラスです。
public class ColorParam extends Color { public ColorParam(String s) { super(getRGB(s)); } private static int getRGB(String s) { if (s.charAt(0) == '#') { try { Color c = Color.decode("0x" + s.substring(1)); return c.getRGB(); } catch (NumberFormatException e) { throw new WebApplicationException(400); } } else { try { Field f = Color.class.getField(s); return ((Color)f.get(null)).getRGB(); } catch (Exception e) { throw new WebApplicationException(400); } } } }
ColorParam
のコンストラクタは一つのString
引数を取ります。
@QueryParam
と@PathParam
の両方とも、以下のJavaクラスのみ使用可能です。
char
を除くすべてのプリミティブ型。Character
を除くプリミティブ型のラッパークラス。- 単一の
String
引数をコンストラクタに取る任意のクラス。 - 単一の
String
引数のvalueOf(String)
という名前のstaticメソッドを持つ任意のクラス。 - Tが既存の条件と一致する
List<T>
,Set<T>
,SortedSet<T>
。パラメータは同一名称で一つ以上の値を持つことがあるため、そのような場合に、すべての値を取得するために使用します。
もし、@DefaultValue
が@QueryParam
と組み合わされておらずクエリパラメータがリクエストに存在しない場合、値は、List
, Set
, SortedSet
の場合には空のコレクション、オブジェクト型の場合はnull、プリミティブ型はそのデフォルト値、になります。
URIパスパラメータ(URI path parameters)はリクエストURIから抽出され、@Path
クラスレベルアノテーションで指定されるURIパステンプレート変数名とパラメータ名が対応します。URIパラメータはメソッド引数にjavax.ws.rs.PathParam
を指定します。以下の例は@Path
変数と@PathParam
の使用方法を示しています。
@Path("/{username}") public class MyResourceBean { ... @GET public String printUsername(@PathParam("username") String userId) { ... } }
このコードでは、URIパステンプレートの変数名username
はprintUsername
メソッドの引数として指定されています。@PathParam
には変数名username
が設定されています。実行時には、printUsername
が呼ばれる前に、username
の値がURIから抽出されてString
にキャストされます。その結果のString
はuserId
変数としてメソッドで利用可能になります。
URIパステンプレートの変数は指定の型にキャストできない場合、JAX-RSランタイムはHTTP 400 ("Bad Request")エラーをクライアントに返します。@PathParam
が指定の型にキャストできない場合、JAX-RSランタイムはHTTP 404 ("Not Found")エラーをクライアントに返します。
@PathParam
パラメータと他のパラメータベースのアノテーション(@MatrixParam
, @HeaderParam
, @CookieParam
, @FormParam
)も@QueryParam
と同様のルールに従います。
Cookieパラメータ(Cookie parameters)は、javax.ws.rs.CookieParam
をパラメータに付与し、cookie関連のHTTPヘッダーで宣言されているcookieから情報を抽出します。ヘッダーパラメータ(Header parameters)は、javax.ws.rs.HeaderParam
をパラメータに付与し、HTTPヘッダーから情報を抽出します。Matrix parametersは、javax.ws.rs.MatrixParam
をパラメータに付与し、URLパスセグメントから情報を抽出します。
フォームパラメータ(Form parameters)は、javax.ws.rs.FormParam
をパラメータに付与し、HTMLフォームに指定されたエンコーディングに http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 で説明される内容に従い、MIMEメディアタイプapplication/x-www-form-urlencoded
のリクエスト表現から情報を抽出します。このパラメータはHTMLフォームのPOSTから情報を抽出するのに役立ちます。
以下の例はデータのPOSTのパラメータからname
を抽出しています。
@POST @Consumes("application/x-www-form-urlencoded") public void post(@FormParam("name") String name) { // Store the message }
クエリとパスパラメータの、パラメータ名と値のマッピングを取得するには、以下のコードを使用します。
@GET public String get(@Context UriInfo ui) { MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); MultivaluedMap<String, String> pathParams = ui.getPathParameters(); }
以下のメソッドは、ヘッダーとcookieパラメータの名前と値を抽出してmapで取得します。
@GET public String get(@Context HttpHeaders hh) { MultivaluedMap<String, String> headerParams = hh.getRequestHeaders(); Map<String, Cookie> pathParams = hh.getCookies(); }
通常、@Context
はリクエストやレスポンスに関連するcontextual Javaクラスを取得するために使用します。
フォームパラメータでは、以下のようなコードを書くことが出来ます。
@POST @Consumes("application/x-www-form-urlencoded") public void post(MultivaluedMap<String, String> formParams) { // Store the message }
29.2.7 Configuring JAX-RS Applications
JAX-RSアプリケーションは、WARファイル内にパッケージされている、少なくとも一つのリソースクラスから構成されます。アプリケーションリソースのベースとなりリクエストに応答するためのURIは二種類の方法のうち一つが使用可能です。
- WAR内に
javax.ws.rs.core.Application
のサブクラスに@ApplicationPath
を使用してパッケージ化する。 - デプロイメント記述子
web.xml
にservlet-mapping
タグを使用する。
29.2.7.1 Configuring a JAX-RS Application Using a Subclass of Application
ベースURIなど、リソースクラスで定義されるRESTリソースが実行される環境をマニュアル設定するには、javax.ws.rs.core.Application
のサブクラスを作成します。ベースURIを設定するにはクラスレベルの@ApplicationPath
を追加します。
@ApplicationPath("/webapi") public class MyApplication extends Application { ... }
以前の例では、ベースURIに/webapi
を設定しており、アプリケーション内で定義されるすべてのリソースは/webapi
に関連付くいう意味になります。
デフォルトでは、アーカイブの全リソースがリソースとして処理されます。JAX-RSランタイムでアプリケーションのリソースクラスをマニュアルで登録するにはgetClasses
メソッドをオーバーライドします。
@Override public Set<Class<?>> getClasses() { final Set<Class<?>> classes = new HashSet<>(); // register root resource classes.add(MyResource.class); return classes; }
29.2.7.2 Configuring the Base URI in web.xml
JAX-RSアプリケーションのベースURIをweb.xml
デプロイメント記述子のservlet-mapping
タグに、servletとしてのApplication
クラスを使用して、設定することができます。
<servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/webapi/*</url-pattern> </servlet-mapping>
なお、この設定はApplication
のサブクラスを使用すると@ApplicationPath
で設定されたパスをオーバーライドします。
<servlet-mapping> <servlet-name>com.example.rest.MyApplication</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
29.3 Example Applications for JAX-RS
このセクションではJAX-RSアプリケーションの作成・デプロイ・実行方法を紹介します。JAX-RSアノテーションを使用するシンプルなwebアプリケーションの作成・ビルド・デプロイ・テストに要求される手順を示します。
29.3.1 Creating a Simple RESTful Web Service
このセクションではMavenアーキタイプを使用してRESTful webサービスを作成するためにNetBeasn IDEを使用する方法を紹介します。アーキタイプはアプリケーションのスケルトンを生成するので、それから適切なメソッドを実装します。
アプリケーションのソースはtut-install/examples/jaxrs/hello/
から参照できます*2。
29.3.1.1 To Create a RESTful Web Service Using NetBeans IDE
- Installing the Tutorial Archetypesに記載されているチュートリアルのアーキタイプをインストール済みなことを確認する。
- NetBeans IDEで、
jaxrs-service-archetype
Mavenアーキタイプを使用してsimple web applicationを生成する。このアーキタイプはシンプルな"Hello, World" webアプリケーションを生成します。 HelloWorld.java
ファイルのgetHtml()
を書き換えます。//TODO
コメントを以下のテキストに置き換えます。
@GET @Produces("text/html") public String getHtml() { return "<html lang=\"en\"><body><h1>Hello, World!!</body></h1></html>"; }
Note: 生成されるMIMEタイプはHTMLなので、戻り値にはHTMLタグを使用可能です。
4. Projects
ペインのHelloWorldApplication
プロジェクトを右クリックしてRunを選択します。
これはビルドを行いアプリケーションをGlassFish Serverにデプロイします。
5. ブラウザで以下のURLを開きます。
http://localhost:8080/HelloWorldApplication/HelloWorldApplication
ブラウザが開かれるとHello, World!!
が表示されます。
NetBeans IDEを使用するJAX-RSアプリケーションのデプロイと実行を紹介する他のサンプルアプリケーションは、The rsvp Example Applicationと http://docs.oracle.com/javaee/7/firstcup/doc/ のYour First Cup: An Introduction to the Java EE Platformを参照してください。また、NetBeans IDEチュートリアルサイトの https://netbeans.org/kb/docs/websvc/rest.html の"Getting Started with RESTful Web Services"などにもチュートリアルがあります。このチュートリアルにはデータベースを使用するCRUDアプリケーションを作成するセクションが含まれています。CRUDは永続化ストレージと関係データベースの基本的な4つの機能です。
29.3.2 The rsvp Example Application
rsvp
サンプルアプリケーションはtut-install/examples/jaxrs/rsvp/
*3ディレクトリにあり、このアプリケーションはイベントに出席するかどうかを表明するものです。イベントに招待された人とその返答はJPAを使用してJava DBに格納されます。rsvp
のJAX-RSリソースはステートレスセッションビーンで公開されます。
29.3.2.1 Components of the rsvp Example Application
rsvp
には三つのEJBrsvp.ejb.ConfigBean
, rsvp.ejb.StatusBean
, rsvp.ejb.ResponseBean
があります。
ConfigBean
はデータベースのデータを初期化するシングルトンセッションビーンです。
StatusBean
はイベントの全招待者の現在のステータスを表示するJAX-RSリソースを公開します。URIパステンプレートがまずクラスに、それからgetEvent
メソッドに宣言されています。
@Stateless @Named @Path("/status") public class StatusBean { ... @GET @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("{eventId}/") public Event getEvent(@PathParam("eventId") Long eventId) { ...
二つの@Path
アノテーションを結合して以下のURIパステンプレートになります。
@Path("/status/{eventId}/")
@GET
を付与されたgetEvent
メソッドはHTTP GETリクエストに応答し、URIパス変数eventId
は@PathParam
変数になります。eventId
変数は個々のイベントのデータベース上の現在のすべての返答を取得するために使用します。
ResponseBean
は個々のイベントの招待の返答を設定するためのJAX-RSリソースを公開します。ResponseBean
のURIパステンプレートは以下のように宣言されています。
@Path("/{eventId}/{inviteId}")
URIパス変数はパステンプレートでeventId
とinviteId
として宣言されています。StatusBean
では、eventId
は個々のイベントを示すユニークIDとして使われます。個々のイベント招待はユニークIDinviteId
を持ちます。これらのパス変数は二つのJAX-RSメソッドResponseBean
のgetResponse
とputResponse
で使用されます。getResponse
メソッドはHTTP GETリクエストに応答するためのメソッドで、招待者の現在の返答状況と返答を変更するためのフォームを表示します。
javaeetutorial.rsvp.rest.RsvpApplication
クラスはクラスレベルにjavax.ws.rs.ApplicationPath
を適用してリソースのルートアプリケーションパスを定義します。
@ApplicationPath("/webapi") public class RsvpApplication extends Application { }
自身の出欠を変更したい招待者はフォームデータをサブミットすると、putResponse
メソッドがHTTP POSTリクエストを処理します。変更後の出欠はHTTP POSTから抽出されてuserResponse
文字列に格納されます。putResponse
メソッドはデータベースの招待者の出欠を更新するためにuserResponse
, eventId
, inviteId
を使用します。
rsvp
のイベント・招待者・出欠はJPAのエンティテイとして表現されています。rsvp.entity.Event
, rsvp.entity.Person
, rsvp.entity.Response
エンティティがそれぞれ、イベント・招待者・出欠、に対応します。
rsvp.util.ResponseEnum
クラスは招待者が取りうるすべての出欠ステータスを表現するenum型です。
また、このwebアプリケーションはマネジードビーンStatusManager
とEventManager
を含み、これはStatusBean
とResponseBean
で公開されるリソースを呼ぶためにJAX-RS Client APIを使用します。 rsvp
で使用されているClient APIの詳細については、"The Client API in the rsvp Example Application"を参照してください。
29.3.2.2 Running the rsvp Example Application
NetBeans IDEとMavenどちらでもrsvp
サンプルアプリケーションのデプロイと実行が可能です。
NetBeans IDEを使用したrsvpサンプルアプリケーションの起動方法
- データベースサーバが起動していなければ、Starting and Stopping the Java DB Serverの手順に従って起動します。
- GlassFish Serverが起動していることを確認します(Starting and Stopping GlassFish Server)。
- Fileメニューから、Open Projectを選択します。
- Open Projectダイアログボックスで以下を選びます。
tut-install/examples/jaxrs
rsvp
フォルダーを選択します。- Open Projectをクリックします。
- Projectsタブで、
rsvp
プロジェクトを右クリックしてRunを選択します。
プロジェクトがコンパイルされ、アセンブリされ、GlassFish Serverにデプロイされます。webブラウザで以下のURLを開きます。
http://localhost:8080/rsvp/index.xhtml
- webブラウザでDuke's BirthdayイベントのEvent statusリンクをクリックします。
現在の招待者と出欠状況が確認できます。 - 表のStatusカラムの招待者の現在の出欠をクリックし、出欠を変更し、Update your statusをクリックします。
招待者の新しい出欠状況が表に表示されます。
Mavenを使用したrsvpサンプルアプリケーションの起動方法
- データベースサーバが起動していなければ、Starting and Stopping the Java DB Serverの手順に従って起動します。
- GlassFish Serverが起動していることを確認します(Starting and Stopping GlassFish Server)。
- ターミナルで以下のディレクトリに移動します。
tut-install/examples/jaxrs/rsvp/
- 以下のコマンドを実行します。
mvn install
このコマンドは、ビルド・アセンブル・GlassFish Serverへのrsvp
のデプロイを行います。 - 以下のURLでブラウザを開きます。
http://localhost:8080/rsvp/
- webブラウザでDuke's BirthdayイベントのEvent statusリンクをクリックします。
現在の招待者と出欠状況が確認できます。 - 表のStatusカラムの招待者の現在の出欠をクリックし、出欠を変更し、Update your statusをクリックします。
招待者の新しい出欠状況が表に表示されます。
29.3.3 Real-World Examples
たいてのブログサイトはRESTful webサービスを使用しています。そうしたサイトは、他のリソースへのリンクを含むRSSやAtom形式のXMLファイルをダウンロードが可能です。RESTライクの開発者向けインタフェースを使用する他のwebサイトやwebアプリケーションにはTwitterやAmazon S3などがあります。Amazon S3では、REST風なHTTPインターフェースもしくはSOAPインタフェースのどちらかを使用して、バケットやオブジェクトの作成・一覧取得・検索が可能です。JerseyのサンプルにはRESTfulインタフェースのストレージサービスが含まれています。
29.4 Further Information about JAX-RS
RESTful webサービスとJAX-RSのより詳細な情報については以下を参照してください。
- "Fielding Dissertation: Chapter 5: Representational State Transfer (REST)":
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm - RESTful Web Services, by Leonard Richardson and Sam Ruby, available from O'Reilly Media at
http://shop.oreilly.com/product/9780596529260.do - JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services:
http://jcp.org/en/jsr/detail?id=339 - Jersey project:
https://jersey.java.net/
関連リンク
- The Java EE 7 Tutorialのテキトー翻訳まとめ - Qiita - Java EE 7 Tutorialのうち、自分がテキトー翻訳したものの一覧