2.12. RESTful Web サービス

2.12.1. RESTful Webサービス・プロジェクトの作成

2.12.1.1. JAX-RS 2.1プロジェクトの作成
(1)新規プロジェクトから作成
メニューから ファイル新規プロジェクトを選択し、新規プロジェクトダイアログを表示します。
新規プロジェクト画面のWeb配下の 動的 Web プロジェクトを選択し、次へをクリックします。

新規プロジェクト Web 動的 Web プロジェクト

プロジェクト名を入力し、構成変更をクリックします。

動的 Web プロジェクト プロジェクト名

プロジェクト・ファセットJAX-RS (REST Web サービス) 2.1 を選択し、OK を押します。

プロジェクト・ファセット JAX-RS (REST Web サービス) 2.1 選択

次の Javaページでは、ソース・フォルダなどを変更可能ですが、 特に変更の必要が無い場合、次へで先に進んでください。
JAX-RS Capabilitiesページでライブラリー構成を無効 を選択し、Update Deployment Descriptor を選択し、サーブレット情報 に以下の内容を入力します。

JAX-RS Capabilities Update Deployment Descriptor 選択

項目
説明
JAX-RS servlet name
必須。JAX-RSサーブレット名を設定します。
JAX-RS servlet class name
必須。org.glassfish.jersey.servlet.ServletContainerを設定します。
URL マッピング・パターン
JAX-RSサーブレットにマッピングするURLパターンを設定します。通常は[/jaxrs/*]を設定します。
終了 をクリックすると、JAX-RS(REST Web サービス) 2.1 ファセットを持つ動的Webプロジェクトが以下のようなディレクトリ構成で作成されます。

プロジェクト・エクスプローラー 動的Webプロジェクト ディレクトリ構成

(2)既存の動的WebプロジェクトからRESTful Webサービスへ変換
既存の動的WebプロジェクトにJAX-RS(REST Web サービス) ファセットの追加と変更ができます。
既存動的Webプロジェクトを選択して、右クリックして表示されるプロジェクトの プロパティーダイアログで プロジェクト・ファセットを選択します。

既存動的Webプロジェクト プロパティーダイアログ プロジェクト・ファセット 選択

JAX-RS (REST Web サービス) 2.1 を選択し、OK をクリックします。

プロジェクト・ファセット JAX-RS (REST Web サービス) 2.1 選択

web.xml を開き、以下のように JAX−RSサーブレットの情報を追加します。

ソース:web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>RestSample</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/jaxrs/*</url-pattern>
  </servlet-mapping>
</web-app>
項目
説明
servlet-name
必須。JAX-RSサーブレット名を設定します。
<servlet>下の<servlet-name>と<servlet-mapping>下の<servlet-name>に同じ値を設定してください。
servlet-class
必須。org.glassfish.jersey.servlet.ServletContainerを設定します。
load-on-startup
JAX-RSサーブレットの初期化順序を設定します。通常は[1]を設定します。
url-pattern
JAX-RSサーブレットにマッピングするURLパターンを設定します。通常は[/jaxrs/*]を設定します。

2.12.2. JAX-RSのアノテーション

JAX-RS カテゴリに所属するアノテーションについては、 [ 開発環境の構築(WebOTX Developer) > アノテーション定義支援ツール > サポートするアノテーション > JAX-RSアノテーション ] をご覧ください。

2.12.3. ルートリソースクラス

ルートリソースクラスは、リソースメソッド、サブリソースメソッド、またはサブリソースロケータのどれかを一つ以上持ち、クラスレベルでPathアノテーションでアノテートされたJavaのpublicのクラスです。 ルートリソースはRESTful Webサービスに提供するリソースのルートで、他のリソースの入り口になります。

ルートリソースクラスの例を下記に示します。
  1 package com.nec.webotx.ws.rest.samples.helloworld.resources;
  2 
  3 import javax.ws.rs.GET;
  4 import javax.ws.rs.Produces;
  5 import javax.ws.rs.Path;
  6 
  7 // The Java class will be hosted at the URI path "/helloworld"
  8 @Path("/helloworld")
  9 public class HelloWorldResource {
 10 
 11     // The Java method will process HTTP GET requests
 12     @GET
 13     // The Java method will produce content identified by the MIME Media
 14     // type "text/plain"
 15     @Produces("text/plain")
 16     public String getClichedMessage() {
 17         // Return some cliched textual content
 18         return "Hello World";
 19     }
 20 }
2.12.3.1. ライフサイクル
ルートリソースクラスのライフサイクルは以下の三種類があります。
2.12.3.2. コンストラクタ
ルートリソースクラスは、publicデフォルトコンストラクタ(明示的に宣言されないコンストラクタ)も含めて、少なくとも一つ以上のpublicコンストラクタを持つ必要があります。 コンストラクタのパラメータで使用できるインジェクション用アノテーションと、オプションのアノテーションの組み合わせは表1.2.15.3-1を参照ください。

パラメータを持つコンストラクタの例を次に示します。
@Path("ResourceTest1")
public class Resource1{
    private String query1;
    public Resource1(@Encoded @DefaultValue("abc") @QueryParam("queryParam1") String query) {
    query1 = query;
}	
@GET
@Path("/queryParam1Value")
    public String getQuery1Value() {
        return "query1=" + query1;
    }
}
この例では、クライアントからURL http://sample.com/example/ResourceTest1/queryParam1Value?queryParam1=queryValueでアクセスすると、queryValueを返却します。
2.12.3.3. フィールドおよびbeanプロパティ
ルートリソースクラスのフィールドおよびbeanプロパティで使用できるアノテーションと、オプションのアノテーションの組み合わせを次の表に示します。JAX-RSエンジンは、ルートリソースクラスをインスタンス化する際に、アノテーション定義されたフィールドおよびbeanプロパティに値をインジェクトします。表にあるアノテーションの意味は[アノテーションのパラメータ]で説明します。
項番 インジェクション用アノテーション オプションのアノテーション
Encoded DefaultValue
1 MatrixParam
2 QueryParam
3 PathParam ×
4 CookieParam ×
5 HeaderParam ×
6 FormParam ×
7 Context × ×
○:インジェクション用のアノテーションと組み合わせて使用できることを示します。
×:インジェクション用のアノテーションが使用できないことを示します。

ルートリソースクラスのフィールドで@Encodedアノテーションを使用する例を次に示します。
private @Encoded @DefaultValue("value1") @QueryParam("id") String id;
URLで“会社”をUTF-8でencodeしたパラメータの値“%E4%BC%9A%E7%A4%BE”でアクセスすると (http://sample.com/example/ResourceTest3/queryParam1Value?id=%E4%BC%9A%E7%A4%BE) リソースクラスで取得できるidの値は“%E4%BC%9A%E7%A4%BE”となり、encodeされた内容になります。
@Encoded アノテーションを使用しない場合、元の文字列“会社”で取得できます。

beanプロパティの@DefaultValueと組み合わせの例:
private String property1;
@DefaultValue("10") @QueryParam("paramProperty1")
public void setProperty1(String property1) {
  this.property1 = property1;
}
この例では、URLの“paramProperty1”QueryParamの値を自動的にproperty1にインジェクションします。
2.12.3.4. リソースメソッド
リソースメソッドは、JAX-RS仕様で定義されたリクエストメソッド識別子でアノテートされたルートリソースクラスのpublicメソッドです。ルートリソースクラスは、一つ以上のリソースメソッドを持つことができます。
JAX-RS仕様で定義されたリクエストメソッド識別子は[HTTPメソッド]を参照して下さい。

リソースメソッドの例を次に示します。
@Path("resource_method")
public class ResourceMethodResource {
	@GET
	public String resourceMethod() {
		return "this is a resource method.";
	}
}
ルートリソースクラスResourceMethodResourceのメソッドresourceMethod()はリソースメソッドです。 クライアントからURI「resource_method」にアクセスする時、JAX-RSエンジンはそのメソッドを呼び出します。
2.12.3.5. サブリソースメソッド
@Pathアノテーションでアノテートされたリソースメソッドをサブリソースメソッドと呼びます。サブリソースメソッドとリソースメソッドの違いは、Pathアノテーションを使用しているか否かになります。

サブリソースメソッドの例を次に示します。
@Path("/resourceTest1")
public class Resource1 {
    public Resource1(){
    }
...
    @GET
    @Path("/testPathParam/{arg1}/{arg2}")
    public String listPathParam(@PathParam("arg1") String arg1,@PathParam("arg2") String arg2) {
        return "arg1="+arg1+" and arg2="+arg2;
    }
...
}
listPathParamメソッドはサブリソースメソッドです。 /resourceTest1/testPathParam/{arg1}/{arg2}のURIにリクエストすると、listPathParam()はそのリクエストを処理します。
2.12.3.6. サブリソースロケータ
サブリソースロケーターは、リクエストメソッド識別子が適用されず、@Pathアノテーションのみでアノテートされたルートリソースクラスのメソッドです。 サブリソースロケータは、HTTPリクエストに対する残りの処理を行うサブリソースクラスを返却します。サブリソースクラスについては、[サブリソースクラス] を参照して下さい。

ルートリソースクラスのサブリソースロケータの例を次に示します。
@Path("/resourceTest1")
public class Resource1 {
    @Path("/testSubResourceLocator/{id}")
    public Resource1_1 getResource1_1(@PathParam("id") String id){
        return new Resource1_1(id);
    }
...
}
対応するサブリソースクラスの例を次に示します。
public class Resource1_1 {
    private String resourceID;
    public Resource1_1(String id){
        resourceID = id;
  }    
    @GET
    public String getDetails(){
        return "This resource id is "+resourceID;
    }
}
この例では、ルートリソースクラスResource1はHTTPリクエストを直接処理しません。サブリソースロケータgetResource1_1が返すサブリソースクラスResource1_1がそのリクエストを処理します。

また、以下のようにオブジェクトではなくクラスを返すこともできます。
@Path("/resourceTest1")
public class Resource1 {
    @Path("/testSubResourceLocator/{id}")
    public Resource1_1 getResource1_1(@PathParam("id") String id){
        return Resource1_1.class;
    }
...
}
クラスを返した場合、ルートリソースクラスと同様にJAX-RSランタイムによってインスタンス化され管理されます。そのためサブリソースロケータが返すクラスはルートリソースクラスと同様に適切なパブリック・コンストラクターを持つ必要があります。

2.12.4. サブリソースクラス

サブリソースクラスは、リソースメソッド、サブリソースメソッド、またはサブリソースロケータのどれかを一つ以上持ち、クラスレベルで@Path アノテーションでアノテートされていないJava のクラスです。
サブリソースクラスは、サブリソースロケータから移譲されたリクエストを直接処理するか、同じ仕組みによって、さらにサブリソースクラスにリクエストを移譲します。

サブリソースクラスの例を次に示します。
public class Resource1_1 {
    private String resourceID;
    public Resource1_1(String id){
        resourceID = id;
  }    
    @GET
    public String getDetails(){
        return "This resource id is "+resourceID;
    }
}
サブリソースクラスのインスタンスは、JAX-RSエンジンによって生成されません。サブリソースクラスは、対応するサブリソースロケータでインスタンス化する必要があります。
2.12.4.1. ライフサイクル
サブリソースクラスのインスタンスは、JAX-RSエンジンによって生成されません。 サブリソースクラスは、対応するサブリソースロケータでインスタンス化する必要があります。このため、サブリソースロケータまたはサブリソースクラスで、コンストラクタのパラメータ、フィールド、およびbeanプロパティを初期化する必要があります。
2.12.4.2. コンストラクタ
サブリソースクラスのコンストラクタのパラメータでは、JAX-RS仕様のアノテーションを使用しないでください。使用されている場合は無視されます。
2.12.4.3. フィールドおよびbeanプロパティ
JAX-RS仕様のアノテーションをサブリソースクラスのフィールドおよびbeanプロパティで使用しないでください。使用されている場合は無視されます。
2.12.4.4. リソースメソッド、サブリソースメソッドおよびサブリソースロケータ
サブリソースクラスのリソースメソッド、サブリソースメソッド、およびサブリソースロケータは、ルートリソースクラスの場合と同じです。

2.12.5. URIテンプレート

@PathアノテーションはリソースのURIを指定するアノテーションです。ルートリソースクラス、サブリソースメソッド、サブリソースロケータに使用できます。

@Pathアノテーションの値は、Webリソースを含むWebアプリケーション(WARファイル)のコンテキストルートに対して相対的なURIを示します。書式は @Path("相対URI") で表されます。
URIは”/”から始まらなくても同じ意味を持ちます。@Path("users/user1")と@Path("/users/user1")は同じURIになります。

URIには変数を使用できます。変数を使用する場合、変数名を{}で囲みます。
例として、@Path("/users/{username}")のように指定します。
username変数の値は、リソースクラスで@PathParamアノテーションを用いて取得できます。

また、URIには正規表現で記述もできます。
例として、@Path("/testRegular1/{username:[a-zA-Z][a-zA-Z_0-9]*}")の場合、usernameの値は「[a-zA-Z][a-zA-Z_0-9]*」と一致します。

PathアノテーションのURIにアスタリスク(*)のみを指定した場合は、リソースメソッドのみを呼び出すことができます。サブリソースメソッド、およびサブリソースロケータを呼び出した場合は、java.lang.StringIndexOutOfBoundsException例外がスローされます。

アノテーションの値は、自動的にエンコードされます。例として、次に示すアノテーションの意味は同じです。
@Path ("widget list/{id}")
@Path ("widget%20list/{id}")

2.12.6. HTTPメソッド

HTTPメソッドアノテーションはHTTPリクエストメソッドの識別子です。リソースメソッドの前に定義することで、そのメソッドは対応するHTTPメソッドのリクエストを処理できます。

2.12.6.1. @GET
HTTPのGETリクエストを処理するメソッドの識別子です。このアノテーションを使用できる対象は下記のとおりです。
2.12.6.2. @POST
HTTPのPOSTリクエストを処理するメソッドの識別子です。このアノテーションを使用できる対象は下記のとおりです。
2.12.6.3. @PUT
HTTPのPUTリクエストを処理するメソッドの識別子です。このアノテーションを使用できる対象は下記のとおりです。
2.12.6.4. @DELETE
HTTPのDELETEリクエストを処理するメソッドの識別子です。このアノテーションを使用できる対象は下記のとおりです。
2.12.6.5. @HEAD
HTTPのHEADリクエストを処理するメソッドの識別子です。このアノテーションを使用できる対象は下記のとおりです。 リソースクラスはHEADリクエストを受け取った時、@HEADでアノテートされたメソッドでHEADリクエストを処理します。@HEADでアノテートされたメソッドが存在しない場合、@GETでアノテートされたメソッドによりHEADリクエストを処理し、レスポンスボディを返信しません。
2.12.6.6. @OPTIONS
HTTPのOPTIONSリクエストを処理するメソッドの識別子です。このアノテーションを使用できる対象は下記のとおりです。 リソースクラスはOPTIONSリクエストを受け取った時、@OPTIONSでアノテートされたメソッドでリクエストを処理します。@OPTIONSでアノテートされたメソッドが存在しない場合、自動生成したmetadataレスポンスを返信します。 metadataはそのルートリソースクラスのwadl情報です。下記に例で説明します。

import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("optionsmethod")
public class OptionsMethodResource {
	@GET
	public String getHello() {
		return "hello";
	}
}
クライアントからHTTP OPTIONSリクエストメソッドでURI「optionsmethod」のリソースをリクエストする時、サーバから下記の内容が返信されます。
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://wadl.dev.java.net/2009/02">
    <doc xmlns:jersey="http://jersey.java.net/" jersey:generatedBy="Jersey: 1.11 12/09/2011 10:27 AM"/>
    <grammars/>
    <resources base="http://{server-name:port}/{context-root}/{url-pattern}/">
        <resource path="optionsmethod">
            <method id="getHello" name="GET">
                <response>
                    <representation mediaType="*/*"/>
                </response>
            </method>
        </resource>
    </resources>
</application>

2.12.7. MIMEタイプ宣言

2.12.7.1. @Consumesアノテーション
@Consumesアノテーションはリソースで受け付けるリクエストのMIMEタイプを表します。以下の箇所で@Consumesアノテーションが使用できます。 エンティティプロバイダについては、[プロバイダ] を参照して下さい。

アノテーションで指定したMIMEタイプ以外は受け付けず例外になリます。その時、INFOで「Mapped exception to response: 415 (Unsupported Media Type)」ログを出力します。HTTPステータスコードに415 Unsupported Media Typeがクライアント返却して、例外javax.ws.rs.WebApplicationExceptionのstackがログに出力します。
2.12.7.2. @Producesアノテーション
@Produces アノテーションはリソースから返却されるメッセージのMIMEタイプを指定します。 以下の箇所で@Producesアノテーションを使用できます。 エンティティプロバイダについては、[プロバイダ] を参照して下さい。
2.12.7.3. 複数なメディアタイプを指定する場合の使用例
複数な出力のMIMEタイプ
      @GET
      Produces({"application/xml", "application/json"})
      public String doGetAsXmlOrJson() {
          ... 
      }
      
品質係数の指定
      @GET
      @Produces({"application/xml; qs=0.9", "application/json"}) 
      public String doGetAsXmlOrJson() { 
          ... 
      }
      

2.12.8. アノテーションの継承

親クラスやインタフェースのメソッドで使用されているJAX-RS仕様のアノテーションは子クラスや実装クラスに継承できます。 アノテーションが継承される条件を次に示します。 親クラスを継承し、かつインタフェースを実装している場合で、アノテーションを継承する条件に両方合致する場合は親クラスのアノテーションを優先しています。

複数の親クラスを継承している場合、または複数のインタフェースを実装している場合、それぞれ最初に継承または実装している親クラスまたはインタフェースのアノテーションが優先されます。アノテーションが継承される例を以下に示します。

1.インタフェース実装の例:
//インタフェース
public interface A {
    @GET
    public String getValue(@QueryParam("query") String query);
}
//インタフェースを実装するルートリソースクラス
@Path("/root/")
public class Resource implements A {
    public String getValue(String query) {…}
}
URL http://sample.com/example/resource/root?query=10 に対するHTTP GETリクエストは、リソースメソッドgetValue()にディスパッチされます。リソースメソッドgetValue()はインタフェースのGETアノテーションを継承しているためです。

2.クラス継承の例
//親クラス
public class ParentClassA {
	@GET
	public String getValue(@QueryParam("query1") String query1){
		return "query1 = "+query1;
	}
}
//子クラス
@Path("/inheretance")
public class SubClass extends ParentClassA {
	public String getValue(String query){
		return query;
	}
}
URL http://sample.com/example/resource/inheretance?query1=10 にアクセスすると、queryの値は10を取得できます。

3.複数インタフェース実装例
public interface InterfaceA {
	@GET
	public String getValue(@PathParam("path1") String path1);
}
public interface InterfaceB {
	@GET
	public String getValue(@QueryParam("query") String query);
}
@Path("/inheretance/{path1}")
public class SubClass implements InterfaceB, InterfaceA{
	public String getValue(String param){
		return param;
	}
}

URL http://sample.com/example/resource/inheretance/aaa?query=456 にアクセスすると、paramの値は456を取得できます。これは、InterfaceBが先にインタフェース実装されており、InterfaceBのアノテーションが優先利用されるためです。 以下のようにInterfaceAを先に記述した場合、
@Path("/inheretance/{path1}")
public class SubClass implements InterfaceA, InterfaceB{
	public String getValue(String param){
		return param;
	}
}
URL http://sample.com/example/resource/inheretance/aaa?query=456 にアクセスすると、paramの値はaaaを取得できます。

2.12.9. アノテーションのパラメータ

リソースクラスのコンストラクターのパラメータの値、フィールドの値とリソースメソッド、サブリソースメソッド、サブリソースロケータのパラメータの値はアノテーションより取得できます。

以下のアノテーションはリソースクラスのコンストラクターのパラメータ、リソースメソッド、サブリソースメソッド、サブリソースロケータのパラメータとクラスのフィールド、Beanプロパティで使用できます。

アノテーションで取得できるパラメータの型の一覧およびDefaultValueアノテーションの組み合わせを次の表に示します。
項番 データ型 アノテーション
PathParam QueryParam MatrixParam CookieParam HeaderParam FormParam Context
1 プリミティブ int ○※1 ×
2 short ○※1 ×
3 long ○※1 ×
4 float ○※1 ×
5 double ○※1 ×
6 char × × × × × × ×
7 byte ○※1 ×
8 boolean ○※1 ×
9 String型の引数を一つ取るコンストラクタを持つ型 ○※1 ×
10 String型の引数を一つ取りその型のインスタンスを返すコンストラクタを持ち、かつstaticなvalueOfまたはfromStringメソッドを持つ型 ※2 ○※1 ×
11 List<T>(Tが上記項番9、10のデータ型) ○※1 × ×
12 Set<T>(Tが上記項番9、10のデータ型) ○※1 × ×
13 Sorted Set<T>(Tが上記項番9、10のデータ型) ○※1 × ×
14 PathSegment ○※1 × × × × × ×
15 コンテキスト型 UriInfo × × × × × × ○※1
16 HttpHeaders × × × × × × ○※1
17 Request × × × × × × ○※1
18 SecurityContext × × × × × × ○※1
19 Providers × × × × × × ○※1
20 ServletConfig × × × × × × ○※1
21 ServletContext × × × × × × ○※1
22 HttpServletRequest × × × × × × ○※1
23 HttpServletResponse × × × × × × ○※1
(凡例)
  ○:インジェクション用アノテーションを使用できることを示します。
  ×:インジェクション用アノテーションを使用できないことを示します。

※1
DefaultValueアノテーションを組み合わせて使用できません。

※2
String型の引数を一つ取りその型のインスタンスを返すコンストラクタを持つ型が、staticなvalueOfメソッドとstaticなfromStringメソッドの両方を持つ場合、型がenum型であれば、staticなfromStringメソッドを使用します。enum型以外であれば、staticなvalueOfメソッドを使用します。
2.12.9.1. @HeaderParamアノテーション
HTTPリクエストヘッダの情報を取得するために使用します。

例:public String getHeaderParam(@HeaderParam("connection") List<String> headers)と定義すると、HTTPリクエストヘッダのコネクション情報をheadersパラメータにインジェクションできます。

@HeaderParamアノテーションを指定できる対象:
ルートリソースクラスのコンス トラクターのパラメーター ルート(サブ)リソースクラスのリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースロケータのパラメータ ルートリソースクラスのフィールド ルートリソースクラスのBeanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメータがないことを示します。
2.12.9.2. @CookieParamアノテーション
HTTP Cookieの情報を取得するために使用します。

例:public String listCookieParam(@CookieParam("sessionid") Cookie arg1,@Context HttpServletResponse response)と定義すると、HTTP CookieのセッションIDをarg1にインジェクションできます。

@HeaderParamアノテーションを指定できる対象:
ルートリソースクラスのコンス トラクターのパラメーター ルート(サブ)リソースクラスのリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースロケータのパラメータ ルートリソースクラスのフィールド ルートリソースクラスのBeanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメータがないことを示します。
2.12.9.3. @MatrixParamアノテーション
リクエストURIのマトリクスパラメータの値を取得するために使用します。

例:public String listMatrixParam(@MatrixParam("bookName") String arg1, @MatrixParam("author") String arg2)と定義すると、 URIに http://sample.com/example/resourceTest1/testMatrixParam;bookName=study;author=Tom を指定した場合、studyをarg1に、Tomをarg2にインジェクションできます。

@MatrixParamアノテーションを指定できる対象:
ルートリソースクラスのコンス トラクターのパラメーター ルート(サブ)リソースクラスのリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースロケータのパラメータ ルートリソースクラスのフィールド ルートリソースクラスのBeanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメータがないことを示します。
2.12.9.4. @QueryParamアノテーション
リクエストURIのクエリパラメータの値を取得するために使用します。

例:public String listPathParam(@QueryParam("arg1") String arg1)) {…} と定義すると、 URIに http://sample.com/example/resources/resource3?arg1=arg1Value を指定した場合、 arg1Valueをarg1にインジェクションできます。

@QueryParamアノテーションを指定できる対象:
ルートリソースクラスのコンストラクターのパラメーター ルート(サブ)リソースクラスのリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースロケータのパラメータ ルートリソースクラスのフィールド ルートリソースクラスのBeanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメータがないことを示します。
2.12.9.5. @PathParamアノテーション
URIのパスの値を取得するために使用します。

例:@Path(“resources/resource3/{arg1}/{arg2}”) public String listPathParam(@PathParam("arg1") String arg1, @PathParam("arg2") String arg2) {…} と定義すると、 URIに http://sample.com/example/resources/resource3/arg1Value/argValue2 を指定した場合、 arg1Valueをarg1に、argValue2をarg2にインジェクションできます。

@PathParamアノテーションを指定できる対象:
ルートリソースクラスのコンス トラクターのパラメーター ルート(サブ)リソースクラスのリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースロケータのパラメータ ルートリソースクラスのフィールド ルートリソースクラスのBeanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメータがないことを示します。
2.12.9.6. @Contextアノテーション
コンテキストの値をインジェクトするために使用します。

以下の型をパラメータに指定できます。
javax.ws.rs.core.UriInfo
URIを構成する各コンポーネント(クエリパラメータやマトリクスパラメータなど)を保持するコンテキストです。HTTPリクエストごとの情報を提供します。
例:
@Path("/root")
public class Resource {
  private @Context UriInfo uriInfo;
  @GET
  public String getValue() {
    String value = this.uriInfo.getQueryParameters().getFirst("query");
    return value;
  }
}
URL http://sample.com/example/root?query=10 にアクセスすると、valueの値は10になります。
javax.ws.rs.core.HttpHeaders
HTTPリクエストのHTTPヘッダを保持するコンテキストです。
例:
@Path("/root")
public class Resource {
  private @Context HttpHeaders httpHeaders;
  @GET
  public String getValue () {
    String value = this.httpHeaders.getRequestHeader("Accept").get(0);
    return value;
  }
}
HTTP Acceptヘッダに"application/xml"を指定し、 URL http://sample.com/example/root"に対するHTTP GETリクエストでアクセスすると、 valueの値はapplication/xmlになります。
javax.ws.rs.core.Providers
デプロイされたWebリソースで動作するプロバイダを保持するコンテキストです。
例:
@Path("/root")
public class Resource {
  private @Context Providers providers;
  @GET
  public String getValue() {
    //providersフィールドから例外マッピングプロバイダを取得します
    return this.providers.getExceptionMapper(RuntimeException.class);
  }
}
URL http://sample.com/example/root にアクセスすると、java.lang.RuntimeExceptionを処理できる例外マッピングプロバイダインスタンスが取得できます。
javax.ws.rs.core.SecurityContext
処理中のHTTPリクエストに関連するセキュリティ情報を保持するコンテキストです。
例:
@Path("/root")
public class Resource {
private @Context SecurityContext securityContext;
  @GET
  public String getValue () {
    String value = "Authentication Scheme: "
        + this.securityContext.getAuthenticationScheme()
        + ", User Principal: " + this.securityContext.getUserPrincipal()
        + ", Is secure: " + this.securityContext.isSecure()
        + ", Is user in role: " + this.securityContext.isUserInRole("admin");
    return value;
  }
}
セキュリティ情報を含むweb.xmlの例を次に示します。
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
  ...
  <security-constraint>
     <web-resource-collection>
       <web-resource-name>Test Resource</web-resource-name>
       <url-pattern>/*</url-pattern>
       <http-method>GET</http-method>
     </web-resource-collection>
     <auth-constraint>
       <role-name>admin</role-name>
     </auth-constraint>
  </security-constraint>
  <login-config>
     <auth-method>BASIC</auth-method>
     <realm-name>jaxrs_server</realm-name>
  </login-config>
  <security-role>
     <role-name>admin</role-name>
  </security-role>
</web-app>
URL http://sample.com/example/root にアクセスすると、web.xmlの設定と実際の認証情報に基づいてセキュリティ情報が取得できます。 WebOTXのJAX-RSではBASIC認証とDigest認証が使用できます。
javax.ws.rs.core.HttpServletRequest
javax.servlet.http.HttpServletRequestはServlet仕様で定義されているクラスです。
例:
@Path("/root")
public class Resource {
  private @Context HttpServletRequest httpRequest;
  @GET
  public String getValue() {
    return this.httpRequest.getParameter("TestParam");
  }
}
URL: http://sample.com/example/root?TestParam=TestValueでアクセスすると、 getValue()よりTestParamパラメータの値TestValueを取得できます。
javax.ws.rs.core.HttpServletResponse
javax.servlet.http.HttpServletResponse はServlet仕様で定義されているクラスです。
例:
@Path("/root")
public class Resource {
  private @Context HttpServletResponse httpResponse;
  @GET
  public void getValue() throws IOException {
    String entity = "Response mentioned using HttpServletResponse";
    httpResponse.setHeader("abc","xyz");
    httpResponse.getOutputStream().write(entity.getBytes());
    httpResponse.getOutputStream().flush();
    httpResponse.getOutputStream().close(); 
  }
}
URL:http://sample.com/example/root にHTTP GETリクエストでアクセスすると、httpResponseフィールドにHttpServletResponseがインジェクトされ、その後HTTP GETリクエストを処理するgetValue()メソッドが呼び出されます。
javax.ws.rs.core.ServletConfig
javax.servlet.ServletConfig はServlet仕様で定義されているクラスです。
例:
@Path("/root")
public class Resource {
  private @Context ServletConfig config;
  @GET
  public String getValue() {
    return this.config.getInitParameter("TestParam");    
  }
}
追加の初期化パラメータ(init-param要素)を含むweb.xmlの例を次に示します。
<web-app ...>
<servlet>
<init-param>
      <param-name>TestParam</param-name>
      <param-value>TestValue</param-value>
</init-param>
……
</servlet>
</web-app>
URL:http://sample.com/example/root にHTTP GETリクエストでアクセスすると、初期化パラメータ"TestParam"の値"TestValue"を取得できます。
javax.ws.rs.core.ServletContext
javax.servlet.ServletContext はServlet仕様で定義されているクラスです。
例:
@Path("/root")
public class Resource {
  private @Context ServletContext context;
  @GET
  public String getValue() {
    return this.context.getInitParameter("TestParam");    
  }
}
コンテキストスコープの初期化パラメータ(context-param要素)を含むweb.xmlを次に示します。
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
  ...
  <context-param>
    <param-name>TestParam</param-name>
    <param-value>TestValue</param-value>
  </context-param>
</web-app>
URL:http://sample.com/example/root にHTTP GETリクエストでアクセスすると、コンテキストスコープの初期化パラメータ"TestParam"の値"TestValue"が取得できます。
javax.ws.rs.core.Request
RFC 2616で規定されるコンテント・ネゴシエーションを行うためのコンテキストを格納しているクラスです。
2.12.9.7. @FormParamアノテーション
HTMLフォームからPOSTされたパラメータは@FormParamでアノテートされたパラメータにインジェクションされます。この時のMIMEタイプは"application/x-www-form-urlencoded"ではなければなりません。

@FormParamアノテーションを指定できる対象:
ルートリソースクラスのコンストラクターのパラメーター ルート(サブ)リソースクラスのリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースメソッドのパラメータ ルート(サブ)リソースクラスのサブリソースロケータのパラメータ ルートリソースクラスのフィールド ルートリソースクラスのBeanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメータがないことを示します。

例:
html form:
<html>
<head>
<meta http-equiv="content-type" content="text/xml;charset=utf-8">
<title> test RESTFulWebService @FromParam</title>
</head>
<body>
<form action="http://localhost:8080/WebProject1/myApplication1/testFormParam" method="post" >
<table>
<tr>
<td>FirstName:</td>
<td><input type="text" name="firstname"></td>
</tr>
<tr>
<td>Age:</td>
<td><input type="text" name="age"></td>
</tr>
</table>
<input type="submit" value="Submit" >
</form>
</body>
</html>
リソースクラス:
@Path("testFormParam")
public class FormResource {
@POST
@Consumes("application/x-www-form-urlencoded")
public String getFormString(@FormParam("firstname") String name, @FormParam("age") int age){
	return "firstname="+name+";age="+age;
	}
}
FirstName入力ボックスにname1を入力し、age入力ボックスに20を入力した場合、リソースクラスの@FormParamからname1と20を取得できます。
2.12.9.8. @Encodedアノテーション
Encodedアノテーションは、自動でURLにあるパラメータの値をデコードされるのを無効化します。
2.12.9.9. @DefaultValueアノテーション
DefaultValueアノテーションはパラメータのデフォルト値を設定できます。

各アノテーションのパラメータとデフォルト値の対応について、次の表で説明します。
パラメータ DefaultValue使用の結果 備考(リクエストパスに指定パラメータの存在状況によって、DefaultValueの利用状況を説明します)
MatrixParam 対応するParamがリクエストパスに存在しない場合、DefaultValue値が使用されます。(備考欄のAの場合、DefaultValueを使用しない) @リクエストパスに指定パラメータがない場合、DefaultValue値を利用する。例えば、リクエストパスに「;null」あるいは「; 指定パラメータ以外のパラメータ= XXX」を指定する。
Aリクエストパスに指定パラメータがある場合、DefaultValue値を利用しない。指定パラメータに値を与えない場合、値はnullになる。指定パラメータに値を与えた場合はその値を利用する。例えば、リクエストパスに「;指定パラメータ名」しか指定しない場合、値はnullになる。
QueryParam 同上 同上
FormParam 同上 同上
CookieParam 同上 同上
複数のパラメータ値を指定する場合、最後の値を利用する。
HeaderParam 対応するParamがリクエストに存在しない場合、DefaultValue値が使用されます。(備考欄のAの場合、DefaultValueを使用しない) @リクエストパスに指定パラメータがない場合、DefaultValue値を利用する。リクエストパスに一番目に指定するパラメータの値が指定しない場合(「指定パラメータ」のように指定する)、DefaultValue値を利用する。
A一番目のパラメータは指定パラメータで、かつ有効な値を指定する場合、DefaultValue値を利用しない。
PathParam DefaultValueアノテーションを無視します。 --
Context DefaultValueアノテーションを無視します。 --
BeanParam DefaultValueアノテーションを無視します。 --
2.12.9.10. @BeanParamアノテーション
ユーザー定義のBeanのフィールドとプロパティなど情報にパラメータをインジェクションするときに使用します。

例:
public class MyBeanParam {
    @PathParam("p")
    private String pathParam;

    @MatrixParam("m")
    @Encoded
    @DefaultValue("default")
    private String matrixParam;

    @HeaderParam("header")
    private String headerParam;

    private String queryParam;

    public MyBeanParam(@QueryParam("q") String queryParam) {
        this.queryParam = queryParam;
    }

    public String getPathParam() { 
        return pathParam; 
    }
    ...
}
メソッドのパラメータとしてMyBeanParamのインジェクション:
@POST
public void post(@BeanParam MyBeanParam beanParam, String entity) { 
    final String pathParam = beanParam.getPathParam();
    ... 
}
上記の例では、シングルBeanとしてのMyBeanParamにインジェクション@PathParam、@QueryParam、@MatrixParamと@HeaderParamのアグリゲータを示しています。postリソースメソッドで@BeanParamより、Beanに注入されたパスパラメータ("p")の設定値が取得できます。

@BeanParamは(@PathParam、@QueryParam、@MatrixParam、@HeaderParam、@CookieParam、@FormParam)全てのパラメータのインジェクションを含めることができます。

@BeanParamアノテーションを指定できる対象は以下の通りです。
ルートリソースクラスの
コンストラクターの
パラメーター
ルート(サブ)リソースクラスの
リソースメソッドの
パラメータ
ルート(サブ)リソースクラスの
サブリソースメソッドの
パラメータ
ルート(サブ)リソースクラスの
サブリソースロケータの
パラメータ
ルートリソースクラスの
フィールド
ルートリソースクラスの
Beanプロパティ
(凡例)
  ○:指定できることを示します。
  ×:指定できないことを示します。
  −:該当するパラメタがないことを示します。

2.12.10. エンティティパラメータ

リソースメソッドのパラメータのうち、アノテーションでアノテートされていないパラメータをエンティティパラメータと呼びます。エンティティパラメータの値は、HTTPエンティティボディです。HTTPエンティティボディからエンティティパラメータのインスタンスへはエンティティプロバイダで変換しています。エンティティプロバイダの詳細は [プロバイダ] を参照ください。

リソースメソッド、サブリソースメソッド、サブリソースロケータには一つエンティティパラメータのみ定義できます。複数なエンティティパラメータを定義した場合、メソッドの一つ目のエンティティパラメータが有効になります。他のエンティティパラメータは無視されます。使用できるエンティティパラメータの型は提供するエンティティプロバイダに従います。

Javaの型に適合するエンティティプロバイダの詳細は [表1.2.15.12-1] を参照ください。それらのエンティティプロバイダ以外にカスタマイズプロバイダも定義できます。定義方法は [プロバイダ] を参照ください。

以下はエンティティパラメータの型がFile(内蔵エンティティプロバイダを利用します)の場合の例です。内蔵エンティティプロバイダはリクエストボディの内容をFileオブジェクトに変更するので、リソースクラスでリクエストボディの内容を含むFileオブジェクトを利用できます。
@Path("EntityParameter")
public class EntityParameter {
	@POST
	@Path("getFileBody")
	public String getFileBody(File fileBody) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileBody),"UTF-8"));
		String line=null;
		StringBuffer sb = new StringBuffer();
		while((line=br.readLine()) != null){
			sb.append(line);
		}
		return sb.toString();
	}
}

2.12.11. レスポンスの作成

リソースメソッドの処理が完了すると、リソースメソッドの戻り値の型によりHTTPレスポンスボディが生成されます。HTTPレスポンスボディに対応するJavaの型は提供するエンティティプロバイダに従います。 Javaの型に対応するエンティティプロバイダの詳細は表1.2.15.12-1を参照して下さい。 そのJavaの型のインスタンスが返却される時、カスタムエンティティプロバイダは必要ではありません。それらのJavaの型以外の型のインスタンスを返却する時、 カスタマイズエンティティプロバイダの作成が必要です。エンティティプロバイダの作成は [プロバイダ] を参照ください。 HTTPレスポンスメッセージにヘッダなどの情報を設定したい場合、JAX-RS APIに定義されているResponseクラスが使用できます。

2.12.11.1. 内蔵エンティティプロバイダ対応するJavaの型
リソースメソッドの戻りの型が「void」である場合、リクエストが処理した後、エンティティが含まれないとレスポンスコードが204のHTTPレスポンスを返します。また、httpメソッドがGETの場合で戻りの型が「void」である場合、ログにINFOレベルで「A HTTP GET method,{メソッドのsignature}MUST return a non-void type.」というメッセージが出力されます。戻りの型が「void」以外である場合、HTTPレスポンスに対応するエンティティプロバイダが必要です。 表1.2.15.12-1のJavaの型のエンティティプロバイダを使用する場合、他のエンティティプロバイダを作成する必要がありません。

例:Javaの型(java.io.InputStream)の使用例
1.リソースクラス InputStreamResource を定義します。
@Path("/inputStreamRes")
public class InputStreamResource {
	private Map<String, String> fileRecord = new HashMap<String, String>();
	public InputStreamResource() {
		fileRecord.put("id1", "ファイルパス");
	}
	@GET
	@Path("/{fileId}")
	public InputStream getInputStream(@PathParam("fileId") String fileId) {
		FileInputStream inStream = null;
		String filePath = fileRecord.get(fileId);
		if (filePath != null) {
			try {
				inStream = new FileInputStream(filePath);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return inStream;
	}
}
パスパラメータ「fileId」により、対応するFileファイルのInputStreamを取得して返却します。

2.クライアント側が「/inputStreamRes/id1」にアクセスすると、サーバ側はInputStreamのエンティティプロバイダ(InputStreamProvider)を利用して、InputStreamインスタンスをHTTPレスポンスに対応させて返信します。
2.12.11.2. Responseタイプ
HTTPレスポンスの返信時に、HTTPレスポンスメッセージの状態コード、MIMEタイプ、エンティティなどをカスタマイズしたい場合、JAX-RS APIに定義するjavax.ws.rs.core.Responseクラスが利用できます。APIの詳細はJAX-RSのJavaDocを参照ください。

下記はResponseの使用例です。
1.ルートリソースクラスResponseResourceを定義します。
@Path("ResponseResource")
public class ResponseResource {
    @GET
    @Path("helloworld")
    public Response getHelloWorldByResponse() {
	    String entityBody = "HelloWorld";
	    return Response.ok(entityBody, MediaType.TEXT_HTML_TYPE).build();
    }
}
2.クライアント側からGETで「/ResponseResource/helloworld」をリクエストすると、 サブリソーメソッドgetHelloWorldByResponse()はレスポンス状態コード「200」、MIMEタイプ「text/html」、エンティティ「HelloWorld」のレスポンスメッセージを返信します。
2.12.11.3. カスタムエンティティプロバイダ対応するJavaの型
リソースメソッドの戻り型はユーザ実装のJavaクラスが使用できます。その場合、HTTPレスポンスに対応するカスタムエンティティプロバイダを作成する必要があります。カスタムエンティティプロバイダ作成についての詳細は[プロバイダ]を参照ください。

2.12.12. プロバイダ

プロバイダはJSR311に定義する@Providerアノテーションで表記し、JSR311に定義するプロバイダインタフェースを実装するクラスです。プロバイダの機能はプロバイダの種類によって異なります。 プロバイダはエンティティプロバイダ、コンテキストプロバイダと例外マッピングプロバイダの三つの種類があります。

各プロバイダの役割を図に示します。

エンティティプロバイダ 例外マッピングプロバイダ

2.12.12.1. エンティティプロバイダ
エンティティプロバイダは下記の機能を提供します。 (1)の場合のプロバイダはMessageBodyReaderプロバイダを呼び出します。(2)の場合のプロバイダはMessageBodyWriterプロバイダを呼び出します。
内蔵エンティティプロバイダ
WebOTXではいくつかのJavaの型に対応するプロバイダを提供しています(内蔵エンティティプロバイダと呼びます)。エンティティパラメータあるいはリソースメソッドの返却値は内蔵エンティティプロバイダに対応するJavaの型の場合、それらのJavaの型に対してプロバイダを作成する必要はありません。 内蔵エンティティプロバイダに対応するJavaの型と対応のMIMEタイプは下記「表1.2.15.12-1」の説明を参照ください。リソースクラスは表にリストしたJavaの型以外の型を使用する場合、カスタマイズプロバイダを作成する必要があります。

@Consumesと@ProducesのMIMEタイプの設定により、リクエストボディを以下のJavaの型に解析するプロバイダと、以下の型をレスポンスボディに解析するプロバイダを提供しています。
表1.2.15.12-1
項番 Javaの型 Charset(※1) MIMEタイプ
1 byte[] × 任意(*/*)
2 java.lang.String 任意(*/*)
3 java.io.InputStream × 任意(*/*)
4 java.io.Reader 任意(*/*)
5 java.io.File(※2) × 任意(*/*)
6 javax.activation.DataSource × 任意(*/*)
7 javax.xml.transform.Source(※3) × text/xml、application/xml、application/*+xml
8 javax.xml.bind.JAXBElement text/xml、application/xml、application/*+xml
9 MultivaluedMap<String,String> application/x-www-form-urlencoded
10 StreamingOutput (※レスポンスのみ) × 任意(*/*)
11 java.awt.image.RenderedImage × image/*、application/octet-stream
12 org.w3c.dom.Document × pplication/xml、text/xml、*/*
13 XmlRootElementアノテーションおよび/またはXmlTypeアノテーションでアノテートされたJAXBクラス × text/xml、application/xml、application/*+xml
14 javax.mail.internet.MimeMultipart multipart/*
15 JSONフォーマットのデータ形式 application/javascript、application/xml、text/xml
16 java.util.List<T>(※4) text/xml、application/xml、application/*+xml
17 void(レスポンスのみ) 任意(*/*)
18 javax.ws.rs.core.Response(※レスポンスのみ) 任意(*/*)
19 javax.ws.rs.core.GenericEntity<T>(※5) Tに指定した型と同じMIMEタイプになります。
上記のJavaの型とMIMEタイプを使用する場合、内蔵エンティティプロバイダを利用します。

(凡例)
  ○:サポートされているパラメータを示します。
  △:Tに指定した型と同じcharsetであることを示します。
  ×:未サポートのパラメータを示します。
  −:該当しないことを示します。
  任意(*/*):すべてのMIMEタイプをサポートしていることを示します。


※1
Producesアノテーションまたは戻り値にcharsetパラメータが含まれる場合、HTTPレスポンスに変換するときに、その情報がContent-Type HTTPヘッダのcharsetパラメータに反映されるかどうかを示します。
  ○:反映されます。Producesアノテーションおよび戻り値にcharsetパラメータが含まれない場合はUTF-8が仮定されます。
  ×:反映されません。

※2
リソースメソッドのパラメータがjava.io.Fileの場合、RESTful WebServiceで一時ファイルを作成する必要があります。一時ファイルの作成のディレクトリに書込みアクセス権がない場合、WebOTXのserver.logに「java.io.IOException:アクセスが拒否されました」という例外を出力します。

一時ディレクトリの例:

Windowsの場合: C:/Users/{コンピュータ名}/AppData/Local/Temp/

Linuxの場合: /tmp/

※3
次に示す実装クラスを使用できます。
※4
TにはXmlRootElementアノテーションでアノテートされたJAXBクラスを指定できます。

※5
Tにはこの表の項番21以外とエンティティプロバイダのみ以外の型を指定できます。
カスタムエンティティプロバイダ
ユーザ実装のJavaクラスを使用する場合、MessageBodyReaderインタフェースとMessageBodyWriterインタフェースの実装が必要になります。

    カスタムMessageBodyReaderエンティティプロバイダ

カスタムMessageBodyReaderエンティティプロバイダを作成するには、MessageBodyReaderインタフェースを実装し、アノテーション@Providerを付与します。
javax.ws.rs.ext.MessageBodyReader<T>インタフェースはJAX-RS APIに定義されているインタフェースです。
詳細は下表1.2.15.12-2に示します。
メソッド 説明
boolean isReadable(java.lang.Class<?>, java.lang.reflect.Type , java.lang.annotation.Annotation[] , MediaType) MessageBodyReaderの実装クラスは特定のJavaタイプのインスタンスを作成できるかどうかを判断します。

true:作成できます。
false:作成できません。
T readFrom(java.lang.Class<T>,java.lang.reflect.Type, java.lang.annotation.Annotation[],MediaType, MultivaluedMap<java.lang.String,java.lang.String>,java.io.InputStream) InputStreamでTが指定するJavaタイプのインスタンスを作成して、返却します。isReadable()がtrueの場合のみ、そのメソッドをコールします。
下記の例はユーザ実装のJavaクラスのNamePasswordBeanのMessageBodyReaderエンティティプロバイダです。
リソースクラスにNamePasswordBeanのインスタンスをエンティティパラメータあるいは返却値とする場合、そのプロバイダを利用します。

例:
  @Provider
 public class NamePasswordBeanReader implements MessageBodyReader<NamePasswordBean> {

	@Override
	public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2,MediaType arg3) {
		return arg0 == NamePasswordBean.class;
	}

	@Override
	public NamePasswordBean readFrom(Class<NamePasswordBean> arg0, Type arg1,Annotation[] arg2, MediaType arg3, MultivaluedMap<String, String> arg4, InputStream arg5) throws IOException, WebApplicationException {
		//NamePasswordBeanインスタンスを作成。
                ……
	}
}
 
プロバイダがリクエストから特定のMIMEタイプのエンティティのみ処理するには、クラスレベルで@Consumesアノテーションが必要になります。@Consumesアノテーションの値はプロバイダがサポートするMIMEタイプです。@Consumesアノテーションを設定しない場合、任意(*/*)のMIMEタイプになります。

(1)MessageBodyReaderエンティティプロバイダのマッチルール


複数のMessageBodyReaderエンティティプロバイダが存在する時、マッチルールによってプロバイダを検索します。

下記はマッチルールの概要説明です。
(1):HTTPリクエストから「Content-Type」ヘッダの値を取得します。取得できない場合、「application/octet-stream」とします。
(2):リソースメソッドに定義するリクエストエンティティボディから対応するJavaの型を取得します。
(3):(1)に取得するMIMEタイプをサポートするプロバイダの集合を取得します。

マッチルールは下記に従います。
「x/y < x/* < */*」 特定のMIMEタイプをサポートするプロバイダは、全てのMIMEタイプをサポートするプロバイダより判断(使用)を優先します。

(4):(3)から選択した各プロバイダのisReadable()メソッドをコールし、「true」を返却するプロバイダを使用します。複数のプロバイダがisReadable()で「true」を返却する場合は、各プロバイダの@Priorityアノテーションの引数で指定された数値が一番小さいプロバイダを使用します。@Priorityアノテーションがついていない場合はデフォルト値であるjavax.ws.rs.Priorities.USER(5000)が適応されます。数値が同じ場合は、サブクラスに先に追加されたプロバイダを使用します。
(5):適当なプロバイダを選択できない場合は、例外が発生し、ログに「A message body reader for Java class {ユーザ実装のJavaクラス}, and Java type class {ユーザ実装のJavaクラス}, and MIME media type {MIMEタイプ} was not found」を出力します。HTTPステータスコード415が返されます。

    カスタムMessageBodyWriterエンティティプロバイダ
カスタムMessageBodyWriterエンティティプロバイダを作成するには、MessageBodyWriterインターフェイスの実装とアノテーション@Providerの付与が必要です。
javax.ws.rs.ext.MessageBodyWriter<T>インタフェースはJAX-RS APIに定義されているインタフェースです。

クラス名/インタフェース 説明
public interface MessageBodyWriter<T> -
メソッド -
boolean isWriteable(java.lang.Class<?>,java.lang.reflect.Type, java.lang.annotation.Annotation[], MediaType) MessageBodyWriterの実装クラスが特定のJavaタイプのインスタンスをHTTPレスポンスに変換できるかどうかを判断します。 true:変換できます。false:変換できません。
long getSize(T,java.lang.Class<?>,java.lang.reflect.Type, java.lang.annotation.Annotation[], MediaType) writeTo()メソッドをコールする前、TのインスタンスをHTTPレスポンスエンティティにシリアライズするバイトの長さが返却されます。 「-1」:全てのバイトの長さ
void writeTo(T,java.lang.Class<?>, java.lang.reflect.Type,java.lang.annotation.Annotation[], MediaType,MultivaluedMap<java.lang.String,java.lang.Object>, java.io.OutputStream) エンティティにシリアライズします。isWriteable()がtrueの場合のみ、そのメソッドをコールします。
下記の例はユーザ実装のJavaクラスであるNamePasswordBeanのMessageBodyWriterエンティティプロバイダです。
リソースクラスはNamePasswordBeanのインスタンスを返却する時、そのプロバイダが利用できます。
例:
 @Provider
public class NamePasswordBeanWriter implements MessageBodyWriter<NamePasswordBean> {

	@Override
	public long getSize(NamePasswordBean arg0, Class<?> arg1, Type arg2,Annotation[] arg3, MediaType arg4) {
		return -1;
	}

	@Override
	public boolean isWriteable(Class<?> classType, Type arg1, Annotation[] arg2,MediaType arg3) {
		return classType == NamePasswordBean.class;
	}

	@Override
	public void writeTo(NamePasswordBean arg0, Class<?> arg1, Type arg2,Annotation[] arg3, MediaType arg4,MultivaluedMap<String, Object> arg5, OutputStream arg6) throws IOException, WebApplicationException {
		// NamePasswordBeanのインスタンスをシリアライズするロジック
     …………
	}
}
 
そのプロバイダは特定のタイプのレスポンスボディを返す時、クラスレベルで@Producesアノテーションが必要になります。レスポンスを返信する時、@Producesアノテーションの値はレスポンスのコンテントタイプ(content-type)とします。@Producesアノテーションを設定しない場合、「All media type(*/*)」はレスポンスのコンテントタイプ(content-type)とします。

(1)MessageBodyWriterエンティティプロバイダのマッチルール


複数のMessageBodyWriterエンティティプロバイダが存在する時、マッチルールによってプロバイダの検索を行います。
下記はマッチルールの概要説明です。


XML
ユーザ実装のJavaクラスを使用する場合、カスタムエンティティプロバイダの作成が必要ですが、カスタムエンティティプロバイダを作成せずに、XMLデータ形式で送受信することもできます。この時、XMLデータ形式はJAXB (JSR 222 implementation)で扱います。
JAXBでXMLを扱う場合、2つの方法があります。1つは「JAXBアノテーション」を利用してJavaの型とXMLデータ形式を対応させます。
もう一つは「javax.xml.bind. JAXBElement<T>」クラスを利用して、Javaの型とXMLデータ形式を対応させます。

    JAXBアノテーション

ユーザ実装のJavaクラスにこのアノテーションを付与します。リソースメソッドの返却値あるいはエンティティパラメータは、このユーザ実装のJavaクラスを利用する場合、エンティティプロバイダを利用して、XMLデータ形式のリクエストボディからそのユーザ実装のJavaクラスのインスタンスに変換します。あるいは、そのユーザ実装のJavaクラスのインスタンスからXMLデータ形式のレスポンスボディに変換します。

下記にRESTful Webサービスの例で説明します。
(1)ユーザ実装のJavaクラスであるPlanetクラスを定義します。このクラスのインスタンスはリソースメソッドの返却値として、クライアント側へ返却します。
   @XmlRootElement
   public class Planet {
       public int id;
       public String name;
       public double radius;
   }
  
PlanetクラスにはJAXBに定義するアノテーションが使用できます。

(2)リソースクラスを定義。
   @Path("planet")
   public class Resource {
   
       @GET
       @Produces(MediaType.APPLICATION_XML)
       public Planet getPlanet() {
           Planet p = new Planet();
           p.id = 1;
           p.name = "Earth";
          p.radius = 1.0;  
          return p;
      }
 }
  
ResourceクラスにリソースメソッドgetPlanet()を定義する@Producesアノテーションを使用して「application/xml」を設定します。
クライアントがそのリソースをリクエストすると、下記のXMLがレスポンスボディとして返却されます。
  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <planet>
      <id>1</id>
      <name>Earth</name>
      <radius>1.0</radius>
   </planet>
  
  「JAXBアノテーション」方式を利用し、ユーザ実装のJavaクラスにJAXBに定義するアノテーションを付与した場合、リソースメソッドの@Producesアノテーションを使用してMIMEタイプを「text/xml、application/xml 、application/*+xml」に設定する必要があります。

  @Producesアノテーションを設定しない場合、デフォルトで「application/xml」が使用されます。

    JAXBElementクラス

JAXBアノテーションを使用せずJavaの型とXMLを対応するには、javax.xml.bind.JAXBElement<T>クラスを使用します。

下記の例で使用方法を説明します。
(1)ユーザ実装のJavaクラスであるPlanetクラスを定義します。このクラスのインスタンスはリソースメソッドの返却値として、クライアント側へ返却します。
   public class Planet {
       public int id;
       public String name;
       public double radius;
   }
  
(2)リソースクラスを定義します。
   @Path("planet")
   public class Resource {
       @GET
       @Produces(MediaType.APPLICATION_XML)
       public JAXBElement<Planet> getPlanet() {
           Planet p = new Planet();
           p.id = 1;
           p.name = "Earth";
          p.radius = 1.0;
  
          return new JAXBElement<Planet>(new QName(“myplanet”), Planet.class, p);
      }
   }
  
javax.xml.bind.JAXBElementを利用する場合、リソースメソッドgetPlanet()の返却値はJAXBElement<Planet>に変更してください。カスタムPlanetクラスのインスタンスを作成し、JAXBElementのコンストラクタのパラメータとして利用します。
JAXBElementのコンストラクタのパラメータQNameはXMLデータ形式のルート要素です。

クライアントへ返信するレスポンスボディを下記に示します。
  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <myplanet>
        <id>1</id>
        <name>Earth</name>
        <radius>1.0</radius>
    <myplanet>
  
リソースクラスにJAXBElement方式を使用する場合、@Producesアノテーションを使用してMIMEタイプを「text/xml、application/xml 、application/*+xml」に設定する必要があります。

@Producesアノテーションを設定しない場合、デフォルトで「application/xml」が使用されます。



JSON

    JSONObject/JSONArrayクラス

JSONObjectとJSONArrayクラスを利用して、JSONデータ形式を変換します。

「JSONObject/JSONArray」の方式は上記の「JAXB」の方式より複雑になります。JSONObjectとJSONArrayのAPIは以下を参照してください。
JSONObject:[https://spring.pleiades.io/specifications/platform/8/apidocs/javax/json/jsonobject]
JSONArray:[https://spring.pleiades.io/specifications/platform/8/apidocs/javax/json/jsonarray]

下記にJSONObjectクラスの使用例で説明します。
(1)POJOを定義します
   public class Contact {
  
       public int id;
       public String name;
        
       public Contact(int id, String name) {
           this.name = name;
           this.id = id;
          
      }
  }
  
(2)リソースを定義します
	 @Path("/JSONObject")
	 public class MyJSONObjectResource {
		@GET
		@Produces("application/json")
		public JSONObject getContact() {
			
			Contact contact = new Contact(2, "BOb");
			JSONObject jsonOb = new JSONObject();
			try {
				jsonOb.put("id", contact.id).put("name", contact.name);
			} catch (JSONException e) {
				e.printStackTrace();
			}
			return jsonOb;
		}
   }
  
クライアント側からそのリソースにアクセスした時に返却されるJSONデータ形式を下記に示します。
  {"id":2,"name":"BOb"}
  
2.12.12.2. コンテキストプロバイダ
コンテキストプロバイダはリソースクラスあるいはプロバイダのコンテキストを提供します。
カスタムコンテキストプロバイダを作成する時にはContextResolver<T>インターフェイスを実装する必要があります。また、アノテーション@Providerが必要になります。
javax.ws.rs.ext.ContextResolver<T>インタフェースはJAX-RS APIに定義するインタフェースです。
クラス名/インタフェース 説明
public interface ContextResolver<T> インタフェース
メソッド -
T getContext(java.lang.Class<?> type) Get a context of type T that is applicable to the supplied type.
下記はカスタムJAXB beansが使用するJAXBContextの例です。
    @Provider
   public class JAXBContextResolver implements ContextResolver<JAXBContext> {
   
       private JAXBContext context;
       private Class[] types = {MyJaxbBean.class};
   
       public JAXBContextResolver() throws Exception {
           this.context = 
   	  new JSONJAXBContext( 
  	    JSONConfiguration.natural().build(), types); 
      }
  
      public JAXBContext getContext(Class<?> objectType) {
          for (Class type : types) {
              if (type == objectType) {
                  return context;
              }
          }
          return null;
      }
 }
   
上記の例に、ユーザ実装のJavaクラスであるMyJaxbBeanのJAXBContextプロバイダを定義します。getContext(Class<?> objectType)メソッドではクラスを判断してカスタムJAXBContext返却します。
また、そのプロバイダは特定のMIMEタイプのみサポートする場合、クラスレベルでアノテーション「@Produces」を指定します。
     @Provider
     @Produces(“application/json”)
      public class JAXBContextResolver implements ContextResolver<JAXBContext> {
         ……
      }
   
「@Produces」を付与しない時、全てMIMEタイプをサポートすることを意味します。

注:一つのJavaTypeに対して、エンティティプロバイダとコンテキストプロバイダの両方が処理できる場合、エンティティプロバイダを利用します。
コンテキストプロバイダのマッチルール
コンテキストプロバイダを選択する時、プロバイダのMIMEタイプの設定により、処理必要なMIMEタイプがサポートするプロバイダを取得して、 サポートするMIMEタイプが「x/y < x/* < */*」の順でプロバイダをソートします。そのため特定のMIMEタイプで対応するプロバイダは全てMIMEタイプをサポートするプロバイダより判断(使用)を優先します。
2.12.12.3. 例外マッピングプロバイダ
リソースクラスで例外が発生し、その情報をHTTPレスポンスとしてクライアントに返却する場合、HTTPレスポンスメッセージに対応するプロバイダ(例外マッピングプロバイダ)が必要になります。 例外マッピングプロバイダの作成詳細は下記の[ExceptionMapperの使用]を参照してください。

2.12.13. JAX-RSクライアントAPIのサポート

JAX-RS 2.1では、RESTful Webサービスとの通信のための流暢なJavaベースのAPIであるJAX-RSクライアントAPIが利用できます。Jakarta EE 8の一部であるこの標準APIは、Webサービスの利用を非常に簡単にするために設計されており、簡潔かつ効率的に実装することができます。

クライアントAPIを利用するためには、jersey-client.jarが必要です。クライアントオブジェクトを作成するとき、静的なClientBuilderファクトリメソッドを使用します。下記の例は、クライアントAPIを利用してユーザーを追加します。

例:
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class UserClient {

   private static String serverUri = "http://localhost:80/WSDemo/rest";

private static void addUser() {
     User user = new User("219","山口","25");
     Client client = ClientBuilder.newClient();
     WebTarget target = client.target(serverUri + "/users");
     Response response = target.request().buildPost(Entity.entity(user, MediaType.APPLICATION_XML)).invoke();
     response.close();
}
ClientConfigを利用して独自のフィルターやインターセプタなどProviderをクライアントオブジェクトに登録できます。 以下は、ユーザー独自のフィルターを登録します。

ClientConfig clientConfig = new ClientConfig();
clientConfig.register(MyClientResponseFilter.class);
clientConfig.register(new AnotherClientFilter());
Client client = ClientBuilder.newClient(clientConfig);
クライアントのインスタンスが作成された後は、Webリソースを特定できます。target(uri)メソッドからWebTargetのオブジェクトが返却されます。WebTargetを利用してサーバーのサブリソースを特定できます。 サーバーのWebリソースはクエリパラメターを受け入れる場合は、queryParam()でWebTargetを特定します。

WebTarget webTarget = client.target("http://example.com/rest");
WebTarget resourceWebTarget = webTarget.path("resource");		// URI "http://example.com/rest/resource"
WebTarget helloworldWebTarget = resourceWebTarget.path("helloworld");	//"http://example.com/rest/resource/helloworld".
WebTarget helloworldWebTargetWithQueryParam = helloworldWebTarget.queryParam("greeting", "Hi World!");
次はHTTPリクエストを作成します。リクエストのメディアのタイプを指定したり、ヘッダを設定したりしたい場合は、以下のように行います。

Invocation.Builder invocationBuilder = helloworldWebTargetWithQueryParam.request(MediaType.TEXT_PLAIN_TYPE);
invocationBuilder.header("some-header", "true");
Invocation.Builder のメソッドを利用して、HTTPレスポンスオブジェクトを取得できます。

getの場合
Response response = invocationBuilder.get();
postの場合
Response response = invocationBuilder.post(Entity.entity("A string entity to be POSTed", MediaType.TEXT_PLAIN));
その後は、レスポンスの結果を確認するには
System.out.println(response.getStatus());
System.out.println(response.readEntity(String.class));

2.12.14. フィルターの作成

フィルターはHttpヘッダなどリクエストとレスポンスのパラメータを変更したい場合に使用します。サーバー側のフィルターとクライアント側のフィルター、2種類に分かれています。

2.12.14.1. サーバ側のフィルター:
ContainerRequestFilter
ContainerResponseFilter
2.12.14.2. クライアント側のフィルター:
ClientRequestFilter
ClientResponseFilter

メニュー ファイル > 新規 > その他 を選択し、Web サービス > JAX-RS フィルター を選択し、次へ ボタンをクリックします。

ファイル 新規 その他 Web サービス JAX-RS フィルター 選択

新規 JAX-RS フィルター 画面にフィルタークラスのソース・フォルダパッケージ、クラス名前 を指定し、作成するフィルターの選択 でフィルターの種類を選択します。

新規 JAX-RS フィルター ソース・フォルダ パッケージ クラス名前 入力

Memo
フィルターは JAX-RS 2.1 規範に定義される機能であるため、フィルター作成で選択されるプロジェクトは JAX-RS 2.1 ファセットを持つ必要があります。

終了 ボタンを押すと、JAX-RS フィルタークラスが生成されます。

プロジェクト・エクスプローラー JAX-RS フィルタークラス

2.12.14.3. ContainerResponseFilter
サーバ側のレスポンスフィルターはContainerResponseFilterのクラスから継承してプロバイダーとして登録されます。ほとんどの場合にはリソースメソッドが実行された後で、レスポンスのフィルターが実行されます。
下記のレスポンスフィルター(PoweredByResponseFilter)の例はレスポンスヘッダ"X-Powered-By"の追加を示します。

サーバ側のフィルターは、JAX-RS ランタイムに認識させるために@Provider アノテーションを付与する必要があります。
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;

@Provider
public class PoweredByResponseFilter implements ContainerResponseFilter {
 
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
        throws IOException { 
            responseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
    }
}
2.12.14.4. ContainerRequestFilter
サーバ側のリクエストフィルターはContainerRequestFilterのクラスを継承します。リクエストのヘッダとエンティティを含め、リクエストのパラメターを操作できます。リソースメソッドを実行してレスポンスが生成される前にリクエストフィルターが実行されます。
下記のリクエストフィルター(AuthorizationRequestFilter)の例は特権的なロールでユーザが認証されるかどうかを判定し、認証できない場合リクエストをabortWithメソッドで中断します。レスポンスはパラメーターとしてabortWithメソッドへ渡してリクエストへ応答しますが、レスポンスフィルターが登録された場合レスポンスフィルターが実行されてレスポンスします。

サーバ側のフィルターは、JAX-RS ランタイムに認識させるために@Provider アノテーションを付与する必要があります。
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;

@Provider
public class AuthorizationRequestFilter implements ContainerRequestFilter {
 
    @Override
    public void filter(ContainerRequestContext requestContext)
                    throws IOException {
 
        final SecurityContext securityContext =
                    requestContext.getSecurityContext();
        if (securityContext == null ||
                    !securityContext.isUserInRole("privileged")) {
 
                requestContext.abortWith(Response
                    .status(Response.Status.UNAUTHORIZED)
                    .entity("User cannot access the resource.")
                    .build());
        }
    }
}
2.12.14.5. ClientRequestFilter
クライアント側のリクエストフィルターはClientRequestFilterのクラスを継承します。サーバ側のフィルターと同じように、ClientRequestFilterはレスポンスを中止できます。リクエストはサーバ側へ送信せず、レスポンスを作成して中止メソッドに渡して、リクエストの結果として返却します。
下記のリクエストフィルター(CheckRequestFilter)の例はリクエストを検証してヘッダ(Client-Name)が存在するかどうかをチェックし、存在しない場合はリクエストを中止します。
public class CheckRequestFilter implements ClientRequestFilter {
 
    @Override
    public void filter(ClientRequestContext requestContext)
                        throws IOException {
        if (requestContext.getHeaders(
                        ).get("Client-Name") == null) {
            requestContext.abortWith(
                        Response.status(Response.Status.BAD_REQUEST)
                .entity("Client-Name header must be defined.")
                        .build());
         }
    }
}
2.12.14.6. ClientResponseFilter
クライアント側のレスポンスフィルターはClientResponseFilterのクラスを継承します。サーバ側からレスポンスを受信した時、クライアントのレスポンスフィルターが実行されます。レスポンスがクライアントに返却する前に、サーバーから返却されたレスポンスを再度処理できます。
public class ClientResponseLoggingFilter implements ClientResponseFilter {

	@Override
	public void filter(final ClientRequestContext reqCtx,
			final ClientResponseContext resCtx) throws IOException {
		System.out.println("status: " + resCtx.getStatus());
		System.out.println("media-type: " + resCtx.getMediaType().getType());
}

2.12.15. インターセプターの作成

インターセプターは、入出力ストリームを通じてエンティティーの読み書き処理を行う時に使います。サーバー側とクライアント側は共通APIを利用します。
インターセプターは

二つの種類に分かれています。
メニュー ファイル > 新規 > その他 を選択し、Web サービス > JAX-RS インターセプター を選択し、次へ ボタンをクリックします。

ファイル 新規 その他 JAX-RS インターセプター 選択

新規 JAX-RS インターセプター 画面にインターセプタークラスのソース・フォルダパッケージ、クラス名前 を指定し、作成するインターセプターの選択 でインターセプターの種類を選択します。

新規 JAX-RS インターセプター ソース・フォルダ パッケージ クラス名前 入力

Memo
インターセプターは JAX-RS 2.1 規範に定義される機能であるため、インターセプター作成で選択されるプロジェクトは JAX-RS 2.1 ファセットを持つ必要があります。

終了 ボタンを押すと、JAX-RS インターセプタークラスが生成されます。

プロジェクト・エクスプローラー JAX-RS インターセプタークラス

2.12.15.1. ReaderInterceptor
ReaderInterceptorはエンティティのストリームを読み取る時利用されます。
サーバ側としては、クライアントからのリクエストのエンティティのストリームを読み込んで扱えます。クライアント側としては、サーバ側からのレスポンスのエンティティのストリームを読み込んで扱えます。

例:
public class GZIPReaderInterceptor implements ReaderInterceptor {
 
    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context)
                    throws IOException, WebApplicationException {
        final InputStream originalInputStream = context.getInputStream();
        context.setInputStream(new GZIPInputStream(originalInputStream));
        return context.proceed();
    }
}
2.12.15.2. WriterInterceptor
Writer interceptorsはエンティティの出力ストリームに書き込む場合に利用されます。
サーバ側としては、クライアント側へのレスポンスのエンティティのストリームに書き込み処理を行います。 クライアント側としては、サーバ側へのリクエストのエンティティのストリームに書き込み処理を行います。

例:
public class GZIPWriterInterceptor implements WriterInterceptor {
 
    @Override
    public void aroundWriteTo(WriterInterceptorContext context)
                    throws IOException, WebApplicationException {
        final OutputStream outputStream = context.getOutputStream();
        context.setOutputStream(new GZIPOutputStream(outputStream));
        context.proceed();
    }
}

2.12.16. SpringDI機能のサポート

JAX-RS 2.1の拡張機能としてSpring DI機能をサポートします。この拡張機能によってSpring BeanがJAX-RSのコンポーネントとして利用されます。

JAX-RSリソースはプロキシに依存する以下のSpring機能を利用する場合、 リソースは下記のアノテーションを使用して管理される必要があります。

例:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.springframework.stereotype.Component;
@Component
@Path("/")
public class SomeResource { 
    @Transactional
    @GET
    public void updateResource() {
        // ...
    }.
}
Spring機能を利用する場合は、SpringのjarをWARファイル中のWEB-INF/libに含めた上で、
WebOTXの以下の拡張機能モジュールをクラスパスに指定する必要があります。
クラスパスの指定は、WARファイル中にnec-web.xmlを作成し、以下の内容を追加してください。
<?xml version="1.0" encoding"UTF-8"?>
<nec-web-app>
        <context-root>sse-item-store-webapp</context-root>
	<class-loader delegate="false" extra-class-path="C:/WebOTX/lib/gf-client.jar;C:/WebOTX/modules/jersey-spring4.jar">
		<property name="overrideablejavaxpackages" value="javax.ws.rs,javax.annotation,javax.validation" />
        </class-loader>
	......
</nec-web-app>

2.12.17. 非同期処理

2.12.17.1. サーバ側
非同期処理において、リソースメソッドが長時間の処理後に結果をリターンするような場合、非同期処理モジュールを利用できます。
server-sideの非同期処理モジュールを利用すると、クライアントについてはリクエスト処理の時間を改善できませんが、I/Oへの初期のリクエスト処理スレッドを解放することによって、サーバのスループットを増加でき、解放されたI/Oスレッドは新しいリクエストの接続を受け付けられます。

下記の例はJAX-RS非同期APIを利用して非同期のリソースのメソッドを定義した例です。
@Path("/resource")
public class AsyncResource {
    @GET
    public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
 
        new Thread(new Runnable() {
            @Override
            public void run() {
                String result = veryExpensiveOperation();
                asyncResponse.resume(result);
            }
 
            private String veryExpensiveOperation() {
                // ... very expensive operation
            }
        }).start();
    }
}
非同期処理において、二つのリクエストの間に待ち時間があり、クライアント側でレスポンス待ちを行いたくない場合に、非同期タイムアウトを利用できます。デフォルトの場合、非同期タイムアウトは非同期レスポンス対象に定義・設定されていませんので、明示的に定義する必要があります。

下記はタイムアウトの使用例です。
@GET
public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {
    asyncResponse.setTimeoutHandler(new TimeoutHandler() {
 
        @Override
        public void handleTimeout(AsyncResponse asyncResponse) {
            asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE)
                    .entity("Operation time out.").build());
        }
    });
    asyncResponse.setTimeout(20, TimeUnit.SECONDS);
 
    new Thread(new Runnable() {
 
        @Override
        public void run() {
            String result = veryExpensiveOperation();
            asyncResponse.resume(result);
        }
 
        private String veryExpensiveOperation() {
            // ... very expensive operation that typically finishes within 20 seconds
        }
    }).start();
}
2.12.17.2. クライアント側
クライアントAPIで非同期処理をサポートしています。AsyncInvokerインスタンスを利用して非同期のレスポンスを取得できます。
下記は非同期処理の使用例です。
final AsyncInvoker asyncInvoker = target().path("http://example.com/resource/")
        .request().async();
final Future<Response> responseFuture = asyncInvoker.get();
System.out.println("Request is being processed asynchronously.");
final Response response = responseFuture.get();
    // get() waits for the response to be ready
System.out.println("Response received.");
2.12.17.3. CompletionStageを使用した非同期処理の代替実装
JAX-RS 2.1では、AsyncResponseを使用した非同期処理はCompletionStageを使用して書き換えることができます。 上記の非同期処理をCompletionStageを使用して書き換えた場合は、以下のようになります。
@Path("/resource")
public class AsyncResource {
  @GET
  public CompletionStage<String> asyncGet() {
    CompletableFuture<String> cs = new CompletableFuture<>();
      new Thread(new Runnable() {
        @Override
        public void run() {
          String result = veryExpensiveOperation();
          cs.complete(result);
        }
      private String veryExpensiveOperation() {
        // ... very expensive operation
      }
    }).start();
    return cs;
  }
}
この例では、リソースメソッドでCompletableFutureインスタンスが作成され、返却されます。インスタンスのcompleteメソッドへの呼び出しは、veryExpensiveOperation()が終了した後に実行されます。
2.12.17.4. Reactive Clients
また、JAX-RSは非同期処理に適したクライアントを実装するReactive Client APIを提供しています。Reactive Client APIのrx()メソッドを使用することで複雑な非同期処理を比較的容易に記述することができます。
下記はReactive Client APIの使用例です。
以下の例では、目的地の価格と距離を並行して取得し、希望の条件に一致した場合にのみ予約処理reserveIfAffordableAndWarm()を行います。
thenCombineで指定するアクションは実行する2つの非同期処理が共に完了した後にのみ実行されます。
client = ClientBuilder.newClient()
CompletionStage<Number> csp = client.target("price/{destination}")
    .resolveTemplate("destination", "mars")
    .request()
    .rx()
    .get(Number.class);
CompletionStage<String> csd = client.target("distance/{destination}")
    .resolveTemplate("destination", "mars")
    .request()
    .rx()
    .get(String.class);
csp.thenCombine(csd, (price, distance) ->
reserveIfAffordableAndWarm(price, distance));
2.12.17.5. Executor Service
JAX-RSでは、スレッドプールを使用して複数のタスクを同時に処理できるExecutor Serviceを利用できます。Executor Serviceを利用する手段として、ManagedExecutorServiceとManagedScheduledExecutorServiceが用意されています。
Executor Serviceの例を以下に示します。 ここではManagedScheduledExecutorServiceで定義されたスレッドプールの中でリクエストを非同期に処理することができます。
  @Resource
  ManagedScheduledExecutorService Pool;
  Client client = ClientBuilder.newBuilder().scheduledExecutorService(pool).build();
  Future>String< result = client.target("http://hoge.com").path("xxx").request().async().get(String.class);
  

2.12.18. セキュリティ

JAX-RSではSSL認証とBASIC認証とDigest認証をサポートしています。
クライアント側ではJAX-RS APIを利用してClientBuilderクラスにSSL情報を格納します。ClientBuilderにはKeyStore, TrustStoreなどを定義できます。
SSL情報の設定例は下記の通りです。
SslConfigurator sslConfig = SslConfigurator.newInstance()
        .trustStoreFile("./truststore_client")
        .trustStorePassword("secret-password-for-truststore")
        .keyStoreFile("./keystore_client")
        .keyPassword("secret-password-for-keystore");
 
SSLContext sslContext = sslConfig.createSSLContext();
Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
Response response = client.target("https://example.com/resource").request().get();
クライアントのHTTP認証には、HttpAuthenticationFeatureのインスタンスを利用できますが、HttpAuthenticationFeatureは二つの認証メソッド(basicとdigest)を提供して下記のモードで実行してください。
※認証には関連のbasicとdigestの知識が必要です。
BASIC:認証情報はHTTPリクエストで送信する。
BASIC NON-PREEMPTIVE:サーバ側には401ステータスでリクエストを拒否するだけに認証情報を追加されてリクエストを繰り返す。
DIGEST:HTTPのダイジェスト認証。
UNIVERSAL:認証情報がない上でリクエストを 送信し、サーバ側には401ステータスでリクエストを拒否すると、レスポンスのヘッダ情報(WWW-Authenticate HTTP header.)により、適切な認証を利用してリクエストを繰り返します。
下記はBasicn認証モードの例です
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("user", "superSecretPassword");
下記はBASIC NON-PREEMPTIVE認証モードの例です。
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder()
    .nonPreemptive().credentials("user", "superSecretPassword").build();

2.12.19. Jakarta JSON Processing (JSON-P)

クライアント、サーバ側それぞれに以下の実装例の通り実装することでJSON-Pを使用できます。
下記はJSON-Pを利用してクライアントを構築する例です。
       ClientBuilder.newClient(new ClientConfig()
             .register(JsonProcessingFeature.class)
             .property(JsonGenerator.PRETTY_PRINTING, true));
     
下記はJSON-Pを利用してJAX-RSのアプリケーションを作成する例です。
      public class MyApplication extends ResourceConfig {
          public MyApplication() {
              packages("com.nec.webotx.jersey.examples.jsonp.resource");
              register(LoggingFilter.class);
              property(JsonGenerator.PRETTY_PRINTING, true);
          }
      }
     
web.xmlの例です。
  <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <servlet>
     <servlet-name>com.nec.webotx.jersey.examples.jsonp.MyApplication</servlet-name>
     <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
     <init-param>
         <param-name>javax.ws.rs.Application</param-name>
         <param-value>com.nec.webotx.jersey.examples.jsonp.MyApplication</param-value>
     </init-param>
     <init-param>
         <param-name>javax.json.stream.JsonGenerator.prettyPrinting</param-name>
         <param-value>true</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
     <servlet-name>com.nec.webotx.jersey.examples.jsonp.MyApplication</servlet-name>
     <url-pattern>/*</url-pattern>
   </servlet-mapping>
  </web-app>
  
JSON-P(JSR 353)はポータブルのAPIsを提供してJSONを解析、生成、伝送、クエリします。APIsについては、二つの種類のAPIを提供します。
2.12.19.1. Object Model API
Object Model APIはXMLのDocument Object Model (DOM)と似ていますが、JSONオブジェクトと配列に不変なオブジェクトのモジュールを提供でき、JAVAのタイプ(JsonObject、JsonArray)を利用してオブジェクトのモジュールにJSONを構造できます。
その中に、JsonObjectはマップビューを提供して名前/値のペアのコレクションをアクセスしますが、JsonArrayはリストビューを提供して値のコレクションをアクセスします。
2.12.19.2. 主なObject Model APIのクラス
Class or Interface 記述
Json Jsonの読み書き、生成及びファクトリーのオブジェクト
JsonGenerator ストリームへJSONデータを書き込み
JsonReader ストリームからJSONデータを読み出し
JsonObjectBuilder
JsonArrayBuilder
オブジェクトと配列のモジュールを生成
JsonWriter ストリームへメモリからオブジェクトのモジュールを書き込み
JsonValue
JsonObject
JsonArray
JsonString
JsonNumber
JSONデータの値のタイプ
下記はObject Model APIの実装例です。
      URL url = new URL("http://sample.com/example/?q=java&type=post");
      try (InputStream is = url.openStream();
          JsonReader rdr = Json.createReader(is)) {
          JsonObject obj = rdr.readObject();
          JsonArray results = obj.getJsonArray("data");
          for (JsonObject result : results.getValuesAs(JsonObject.class)) {
              System.out.print(result.getJsonObject("from").getString("name"));
              System.out.print(": ");
              System.out.println(result.getString("message", ""));
              System.out.println("-----------");
          }
     
結果のフォーマットは下記の通りです。
     	{
          "data" : [
              { "from" : { "name" : "xxx", ... }, "message" : "yyy", ... },
              { "from" : { "name" : "ppp", ... }, "message" : "qqq", ... },
              ...
          ],
          ...
      }
     
2.12.19.3. Streaming API
Streaming APIはXML (StAX) のStreaming APIと似ていますが、インターフェースのJsonParserとJsonGeneratorから組み合わせて、JsonParser はストリームを利用してJSONデータを解析するメソッドを含み、JsonGeneratorはアウトプットソースへJSONデータを書きこむメソッドを含みます。
2.12.19.4. 主なStreaming APIのクラス
Class or Interface 記述
Json Jsonの読み書き、生成及びファクトリーのオブジェクト
JsonParser イベントにベースして解析し、ストリームからJSONデータを読み出し
JsonGenerator ストリームへJSONデータを書き込み
下記はObject Model APIの例です。
      URL url = new URL("https://graph.facebook.com/search?q=java&type=post");
      try (InputStream is = url.openStream();
           JsonParser parser = Json.createParser(is)) {
           while (parser.hasNext()) {
             Event e = parser.next();
             if (e == Event.KEY_NAME) {
                   switch (parser.getString()) {
                      case "name":
                          parser.next();
                         System.out.print(parser.getString());
                         System.out.print(": ");
                         break;
                     case "message":
                         parser.next();
                          System.out.println(parser.getString());
                         System.out.println("---------");
                         break;
                  }
               }
           }
       }
     
出力結果はObject Model APIの使用例を参照してください。

2.12.20. Jakarta JSON Binding (JSON-B)

JSON-Bはapplication/jsonやtext/jsonを含む*/jsonまたは*/*+jsonのメディアタイプとすべてのJavaの型に対応するエンティティプロバイダを提供します。複数のエンティティプロバイダが存在する場合、JSON-Bのエンティティプロバイダが基本的に優先されます。ただしJSON-PのJsonValueとそのサブタイプに対応するエンティティプロバイダはJSON-Bより優先されます。また、任意のエンティティプロバイダを優先的に使用したい場合は、@Priorityアノテーションを使用して優先度を設定することで使用できます。
下記の例はjavax.json.stream.JsonParser型に対応するカスタムエンティティプロバイダです。
  @Provider
  public class JsonParserBodyReader implements MessageBodyReader<JsonParser> {
    @Override
    public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2,MediaType arg3) {
      return arg0 == JsonParser.class;
    }
    @Override
    public JsonParser readFrom(Class<JsonParser> arg0, Type arg1,Annotation[] arg2,
          MediaType arg3, MultivaluedMap<String, String> arg4, InputStream arg5) throws IOException, WebApplicationException {
      //JsonParserインスタンスを作成。

    }
  }
この時、エンティティパラメータがJsonValue型であれば、JSON-Pに対応するエンティティプロバイダであるJsonValueBodyReaderが使用されます。一方、エンティティパラメータがJsonParser型であればJSON-Bに対応するエンティティプロバイダであるJsonBindingProviderが使用されます。

2.12.21. Server-Sent Events (SSE)サポート

2.12.21.1. 概要
標準的なHTTPのリクエスト・レスポンスでは、クライアント側はコネクションをオープン後にリクエストを送信しHTTPのレスポンスを受信します。サーバ側はクライアントからのリクエストを受信してレスポンス送信後にコネクションを閉じます。
一方SSEでは、クライアント側がコネクションをオープン後に、サーバ側がコネクションを保持してクライアントへ非同期にデータを送信することを許可します。
データが作成されて利用可能になると、サーバ側からクライアントへ提供・送信します。クライアント側には同じコネクションで送信するため、SSEでは一つのコネクションを利用して複数のメッセージを処理できます。
2.12.21.2. Server-Sent Events API
SSEを利用するには、サーバ側とクライアント側とでそれぞれServer-Sent Events APIを使用します。
WebOTXでは、これまでのJerseyの提供するServer-Sent Events APIに加え、JAX-RS 2.1の提供するServer-Sent Events APIも新たに使用することができます。
2.12.21.3. サーバ実装とクライアント実装(Jersey)
JerseyのServer-Sent Events APIの場合はOutboundEventとInboundEventのエンティティを使用できます。OutboundEventはサーバ側のデータをパッケージするエンティティであり、InboundEventはクライアントにサーバから受信するエンティティです。サーバ側では、リソースメソッドに@Producesアノテーションを使用する事で「text/event-stream」がセットされたOutboundEventエンティティを戻すことができます。
・サーバ側の実装例
     	...
      import org.glassfish.jersey.media.sse.EventOutput;
      import org.glassfish.jersey.media.sse.OutboundEvent;
      import org.glassfish.jersey.media.sse.SseFeature;
      ...
      @Path("events")
      public static class SseResource {
          @GET
          @Produces(SseFeature.SERVER_SENT_EVENTS)
          public EventOutput getServerSentEvents() {
              final EventOutput eventOutput = new EventOutput();
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          for (int i = 0; i < 10; i++) {
                              // ... code that waits 1 second
                              final OutboundEvent.Builder eventBuilder
                              = new OutboundEvent.Builder();
                              eventBuilder.name("message-to-client");
                              eventBuilder.data(String.class,
                                  "Hello world " + i + "!");
                              final OutboundEvent event = eventBuilder.build();
                              eventOutput.write(event);
                          }
                      } catch (IOException e) {
                          throw new RuntimeException(
                              "Error when writing the event.", e);
                      } finally {
                          try {
                              eventOutput.close();
                          } catch (IOException ioClose) {
                              throw new RuntimeException(
                                  "Error when closing the event output.", ioClose);
                          }
                      }
                  }
              }).start();
              return eventOutput;
          }
      }
     
・クライアント側の実装例
      Client client = ClientBuilder.newBuilder()
        .register(SseFeature.class).build();
      WebTarget target = client.target("http://localhost:9998/events");
 
      EventInput eventInput = target.request().get(EventInput.class);
      while (!eventInput.isClosed()) {
          final InboundEvent inboundEvent = eventInput.read();
          if (inboundEvent == null) {
              // connection has been closed
              break;
          }
          System.out.println(inboundEvent.getName() + "; "
              + inboundEvent.readData(String.class));
      }
     
2.12.21.4. サーバ実装とクライアント実装(JAX-RS 2.1)
JAX-RS 2.1のServer-Sent Events APIの場合はSseEventSinkとSseEventSourceを使用できます。サーバー側はクライアントからの接続開始を受け入れ、1つ以上のクライアントにイベントを送信します。クライアント側はサーバー側から送信されたイベントを受信します。
以下の例は、サーバー側はSSE接続を受け入れ、executorスレッドを使用して、接続を閉じる前に3つのイベントを送信します。クライアント側は、SSE接続を開始し、しばらくの間イベントを受信しながらメッセージを読み取ります。
・サーバ側の実装例
     	...
      @GET
      @Path("eventStream")
      @Produces(MediaType.SERVER_SENT_EVENTS)
      public void eventStream(@Context SseEventSink eventSink,@Context Sse sse) {
        executor.execute(() -> {
          try (SseEventSink sink = eventSink) {
            eventSink.send(sse.newEvent("event1"));
            eventSink.send(sse.newEvent("event2"));
            eventSink.send(sse.newEvent("event3"));
          }      
        });
      }
     
・クライアント側の実装例
      WebTarget target = client.target("http://...");
      try (SseEventSource source = SseEventSource.target(target).build()) {
      source.register(System.out::println);
      source.open();
      Thread.sleep(500); // Consume events for just 500 ms
      } catch (InterruptedException e) {
        // falls through
      }
     

2.12.22. 異常の処理

リソースクラスはリクエスト処理時に異常が発生した場合、その情報をHTTPレスポンスとしてクライアント側に返却します。
例外クラスには2つの種類があり、1つはWebApplicationExceptionとそのクラスのサブクラス、もう1つはカスタム例外クラスですが。下記にその二つの例外をレスポンスに変換するルールを説明します。
2.12.22.1. WebApplicationException
リソースクラスで異常が発生した時、その情報はHTTPレスポンスとしてクライアント側に返却するために例外クラスMapperを使用します。例としてクライアントが指定したURLでリソースを見つけられない場合、
「404 not found」レスポンスを返信します。その場合、javax.ws.rs.WebApplicationExceptionのサブクラスNotFoundExceptionを使用します。
NotFoundExceptionの実装例を下記に示します。
public class NotFoundException extends WebApplicationException {
   
   /**
     * Create a HTTP 404 (Not Found) exception.
     *
     * @param message the String that is the entity of the 404 response.
     */
    public NotFoundException(String message) {
        this(message, null);
    }

    /**
     * Create a HTTP 404 (Not Found) exception.
     *
     * @param message the String that is the entity of the 404 response.exception A URI-parameter-based exception for errors with QueryParam.Contain a response with a 404 (Client error) status code.
     *  ParamException.HeaderParamException	A parameter exception for errors with HeaderParam.Contain a response with a 400 (Client error) status code.
     *  ParamException.CookieParamException	A parameter exception for errors with CookieParam.Contain a response with a 400 (Client error) status code.
     *  ParamException.FormParamException	A parameter exception for errors with FormParam.Contain a response with a 400 (Client error) status code.
     * @param notFoundUri the URI that cannot be found.
     */
    public NotFoundException(String message, URI notFoundUri) {
        super(Responses.notFound().
                entity(message).type("text/plain").build());
        this.notFoundUri = notFoundUri;
    }
}
javax.ws.rs.WebApplicationExceptionのサブクラスは以下のとおりです。

異常クラス 説明
ConflictException Create a HTTP 409 (Conflict) exception.
NotFoundException Create a HTTP 404 (Not Found) exception.
ParamException An abstract extension of WebApplicationException for the class of parameter-based exceptions.
ParamException.PathParamException A URI-parameter-based exception for errors with PathParam.Contain a response with a 404 (Client error) status code.
ParamException.MatrixParamException A URI-parameter-based exception for errors with MatrixParam.Contain a response with a 404 (Client error) status code.
ParamException.QueryParamException A URI-parameter-based exception for errors with QueryParam.Contain a response with a 404 (Client error) status code.
ParamException.HeaderParamException A parameter exception for errors with HeaderParam.Contain a response with a 400 (Client error) status code.
ParamException.CookieParamException A parameter exception for errors with CookieParam.Contain a response with a 400 (Client error) status code.
ParamException.FormParamException A parameter exception for errors with FormParam.Contain a response with a 400 (Client error) status code.

また、javax.ws.rs.WebApplicationExceptionクラスも直接使用できます。
2.12.22.2. ExceptionMapperの使用
カスタム例外クラスを定義する場合、カスタム例外クラスはHTTPレスポンスに変換するプロバイダの定義が必要です。カスタム例外マッピングプロバイダを作成するには、
javax.ws.rs.ext.ExceptionMapper<E extends Throwable>インタフェースを実装してください。また、アノテーション「@Provider」をクラスレベルで付与する必要があります。

「404」レスポンスを返信する例外マッピングプロバイダの例は次のようになります。
   @Provider
   public class EntityNotFoundMapper implements
           ExceptionMapper<EntityNotFoundException> {
       public Response toResponse(EntityNotFoundException ex) {
          return Response.status(404).
               entity(ex.getMessage()).
               type("text/plain").
              build();
       }
  }
 
発生例外クラスの型とマッチする例外クラスMapperを使用しますが、一つの例外クラスに対して複数の例外クラスMapperがマッチした場合、以下の選択ルールにより例外クラスMapperを使用します。

2.12.23. warファイルの構成

RESTful Webサービスを含むwarファイルの構成について説明します。
2.12.23.1. warファイルの構成
次の表に示す構成にする必要があります。
ディレクトリ 備考
/

META-INF/
MANIFEST.MF
WEB-INF/
web.xml 作成したweb.xmlです。
classes/ コンパイルしたJavaクラスを格納します。
lib/ コンパイルしたJavaクラスを含むJARファイルを格納します。
(凡例)
−:説明や補足事項が特にないことを示します。
2.12.23.2. ルートリソースクラスの作成
ルートリソースクラスは、コンパイルしたJavaクラスファイル(*.class)として作成します。必要に応じてサブリソースクラスや例外マッピングプロバイダも同様に作成します。

コンパイルしたJavaクラスファイル(*.class)は、warファイルを構成するディレクトリに含めます。次に示すどちらか、または両方に含めてください。 warファイルには、少なくとも一つ以上のルートリソースクラスが含まれる必要があります。
2.12.23.3. JAX-RS機能の配備
JAX-RSがルートリソースクラスとプロバイダクラスを公開するための抽象クラスjavax.ws.rs.core.Applicationを継承し、カスタムApplicationを実装することができます。
クラス名 説明
public class Application Defines the components of a JAX-RS application and supplies additional metadata. A JAX-RS application or implementation supplies a concrete subclass of this abstract class
フィールド -
private static final Set<Object> emptyObjectSet emptyObjectSet = Collections.emptySet()
private static final Set<Class<?>> emptyClassSet emptyClassSet = Collections.emptySet()
メソッド -
public Set<Class<?>> getClasses() Get a set of root resource and provider classes. The default lifecycle for resource class instances is per-request. The default lifecycle for providers is singleton
public Set<Object> getSingletons() Get a set of root resource and provider instances. Fields and properties of returned instances are injected with their declared dependencies Context by the runtime prior to use.

下記はカスタムApplicationの例です。
      package com.nec.jersey.application;
      @ApplicationPath(“resources”)
      public class MyApplication extends Application {
        public Set<Class<?>> getClasses() {
            Set<Class<?>> s = new HashSet<Class<?>>();
            s.add(HelloWorldResource.class);
            return s;
        }
    }
    
その場合の@ApplicationPathに指定する値はweb.xmlの「url-pattern」の値と同じです。

2.12.24. WADL

2.12.24.1. WADLの概要
WADLはWeb Application Description Languageの略称です。対応しているWADLのバージョンは「Web Application Description Language W3C Member Submission 31 August 2009」です。 JAX-RS機能にはWADLファイル生成のみを提供します。リソースのWADLファイルの取得方法は「使用例の説明」を参照して下さい。

W3CのWADL仕様にはユーザが定義したリソースの情報を表示するため、いくつかの要素を定義しています。各要素の詳細は「http://www.w3.org/Submission/wadl/」を参照して下さい。下記はWADLの基本要素の概要の説明です。
要素 説明 仕様章節
application the root element of a WADL description 2.2 Application
doc application」element can have one or more child doc elements that can be used to document that element. this element has two attributes: (1):xml:lang (2):title 2.3 Documentation
grammars The grammars element acts as a container for definitions of the format of data exchanged during execution of the protocol described by the WADL document 2.4 Grammars
resources The resources element acts as a container for the resources provided by the application. 2.5 Resources
resource A resource element describes a set of resources, each identified by a URI that follows a common pattern. 2.6 Resource
resource_type A resource_type element describes a set of methods that, together, define the behavior of a type of resource. 2.7 Resource Type
method A method element describes the input to and output from an HTTP protocol method that may be applied to a resource. 2.8 Method
request A request element describes the input to be included when applying an HTTP method to a resource. 2.9 Request
response A response element describes the output that results from performing an HTTP method on a resource. 2.10 Response
representation A representation element describes a representation of a resource's state. 2.11 Representation
param A param element describes a parameterized component of its parent element. 2.12 Parameter
2.12.24.2. 使用例の説明
リソースクラスからWADLファイルが作成できます。
クライアント側で下記のURLよりリソースのWADLファイルを取得できます。

URL:http://{server-name}:{port}/{context-root}/{url-pattern}/application.wadl

リソースクラスの例を以下に示します。
  @Path("wadlResource")
  public class WADLResource {
	 @GET
	 public String executeGetRequest() {
		//do something
		return "success";
	 }
	 @POST
	 public String executePostRequest() {
		//do something
		return "success";
	 }
  }
  
web.xmlファイルの関連する設定を以下に示します。
  <web-app ……>
     ……
    <servlet>
  	   <servlet-name>wadlTest</servlet-name>
	   <servlet-class>
         org.glassfish.jersey.servlet.ServletContainer
       </servlet-class>
  	    ……
    </servlet>
    <servlet-mapping>
  	   <servlet-name>wadlTest</servlet-name>
  	   <url-pattern>/jersey/*</url-pattern>
    </servlet-mapping>
    ……
  </web-app>
  
クライアント側でURL:「http://{server-name}:{port}/{context-root}/jersey/application.wadl」にアクセスすると、下記のWADLファイルを取得できます。
  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <application xmlns="http://wadl.dev.java.net/2009/02">
     <doc xmlns:jersey=http://jersey.java.net/ …… />
     <grammars/>
     <resources base="http://{server-name}:{port}/{context-root}/{url-pattern}/">
         <resource path="wadlResource">
             <method id="executeGetRequest" name="GET">
                <response>
                    <representation mediaType="*/*"/>
                </response>
             </method>
             <method id="executePostRequest" name="POST">
                 <response>
                     <representation mediaType="*/*"/>
                 </response>
             </method>
         </resource>
     </resources>
    </application>