47.2. JAX-RS API の使用

47.2.1. JAX-RS アノテーションタイプ

標準の JAX-RS API は、値をフィールド、Bean プロパティー、およびメソッドパラメーターに注入するために使用できるアノテーションを指定します。アノテーションは、以下の 3 つのタイプに分割できます。

47.2.2. リクエスト URI からのデータの注入

概要

RESTful Web サービスを設計するためのベストプラクティスの 1 つとして、各リソースに一意の URI を設定する必要があります。開発者はこの原則を使用して、基盤となるリソースの実装に適量の情報を提供できます。リソースの URI テンプレートを設計する場合には、開発者は、リソースの実装に注入できるパラメーター情報を含めるようにテンプレートを作成できます。また、開発者はクエリーおよびマトリックスパラメーターを使用して、情報をリソース実装にフィードすることもできます。

URI のパスからのデータ取得

リソースの URI テンプレートの作成に使用される変数でリソースに関する情報を取得することが一般的なメカニズムです。これは、javax.ws.rs.PathParam アノテーションを使用して実現されます。@PathParam アノテーションには、データの注入元となる URI テンプレート変数を識別する単一のパラメーターがあります。

例47.1「URI テンプレート変数からのデータの注入」 では、@PathParam アノテーションは URI テンプレート変数 color の値が itemColor フィールドにインジェクトされることを指定します。

例47.1 URI テンプレート変数からのデータの注入

import javax.ws.rs.Path;
import javax.ws.rs.PathParam
...

@Path("/boxes/{shape}/{color}")
class Box
{
  ...

  @PathParam("color")
  String itemColor;

  ...
}

@PathParam アノテーションでサポートされるデータ型は、「サポートされるデータタイプ」 で説明されているものとは異なります。@PathParam アノテーションがデータを注入するエンティティーは、以下の型のいずれかでなければなりません。

  • PathSegment

    値は、パスに一致する部分の最後のセグメントになります。

  • List<PathSegment>

    この値は、名前付きの template パラメーターに一致するパスセグメントに対応する PathSegment オブジェクトのリストです。

  • intchar、または long などのプリミティブ
  • 単一の String 引数を受け入れるコンストラクターを持つオブジェクト
  • 単一の String 引数を受け入れる静的 valueOf() メソッドを持つオブジェクト

クエリーパラメーターの使用

Web に情報を渡す一般的な方法は、URI で クエリーパラメーター を使用することです。クエリーパラメーターは URI の最後に表示され、疑問符 (?) で URI のリソース場所部分から区切られます。これらは、名前と値が等号 (=) で区切られた 1 つ以上の名前と値のペアで設定されます。複数のクエリーパラメーターを指定すると、ペアはセミコロン (;) またはアンパサンド (&) で区切られます。例47.2「クエリー文字列のある URI」 は、クエリーパラメーターが含まれる URI の構文を示しています。

例47.2 クエリー文字列のある URI

http://fusesource.org?name=value;name2=value2;...
注記

セミコロンまたはアンパサンドの いずれか を使用してクエリーパラメーターを区切ることができますが、両方は使用できません。

javax.ws.rs.QueryParam アノテーションは、クエリーパラメーターの値を抽出し、それを JAX-RS リソースに注入します。アノテーションでは、パラメーターを 1 つ使用できます。このパラメーターをもとに、値の抽出、指定されたフィールド、Bean プロパティー、またはパラメーターにインジェクトされるクエリーパラメーターの名前が識別されます。@QueryParam アノテーションは、「サポートされるデータタイプ」で説明されている型をサポートします。

例47.3「クエリーパラメーターのデータを使用したリソースメソッド」 は、クエリーパラメーター id の値をメソッドの id パラメーターに注入するリソースメソッドを示しています。

例47.3 クエリーパラメーターのデータを使用したリソースメソッド

import javax.ws.rs.QueryParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
...

@Path("/monstersforhire/")
public class MonsterService
{
  ...
  @POST
  @Path("/{type}")
  public void updateMonster(@PathParam("type") String type,
                            @QueryParam("id") String id)
  {
    ...
  }
  ...
}

HTTP POST/monstersforhire/daikaiju?id=jonas に処理するには、updateMonster() メソッドの typedaikaiju に設定され、idjonas に設定されます。

マトリクスパラメーターの使用

URI クエリーパラメーターと同様に、URI マトリックスパラメーターは、リソース選択用の追加情報を提供できる名前と値のペアです。クエリーパラメーターとは異なり、マトリクスパラメーターは URI のどこにでも置くことができ、セミコロン (;) を使用して URI の階層パスセグメントから区別されます。/mostersforhire/daikaiju;id=jonas には id という 1 つのマトリクスパラメーターがあり、/monstersforhire/japan;type=daikaiju/flying;wingspan=40 には type および wingspan という 2 つのマトリクスパラメーターがあります。

注記

リソースの URI を計算するときには、マトリックスパラメーターは評価されません。そのため、要求 URI /monstersforhire/japan;type=daikaiju/flying;wingspan=40/monstersforhire/japan/flying の処理に適したリソースを見つけるために使用される URI です。

マトリクスパラメーターの値は、javax.ws.rs.MatrixParam アノテーションを使用してフィールド、パラメーター、または Bean プロパティーに注入されます。アノテーションでは、パラメーターを 1 つ使用できます。このパラメーターをもとに、値の抽出、指定されたフィールド、Bean プロパティー、またはパラメーターにインジェクトされるマトリックスパラメーターの名前が識別されます。@MatrixParam アノテーションは、「サポートされるデータタイプ」で説明されている型をサポートします。

例47.4「マトリックスパラメーターのデータを使用するリソースメソッド」 は、マトリクスパラメーター type および id の値をメソッドのパラメーターに注入するリソースメソッドを表しています。

例47.4 マトリックスパラメーターのデータを使用するリソースメソッド

import javax.ws.rs.MatrixParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
...

@Path("/monstersforhire/")
public class MonsterService
{
  ...
  @POST
  public void updateMonster(@MatrixParam("type") String type,
                            @MatrixParam("id") String id)
  {
    ...
  }
  ...
}

HTTP POST/monstersforhire;type=daikaiju;id=whale に処理するには、updateMonster() メソッドの typedaikaiju に設定され、idwhale に設定されます。

注記

JAX-RS は URI の全マトリックスパラメーターを一度に評価するため、URI のマトリックスパラメーターの場所に、制約を適用することはできません。たとえば、/monstersforhire/japan;type=daikaiju/flying;wingspan=40 , /monstersforhire/japan/flying;type=daikaiju;wingspan=40, and /monstersforhire/japan;type=daikaiju; wingspan=40/flying はすべて、JAX-RS API を使用して実装される RESTful Web サービスと同等のものとして処理されます。

URI のデコードの無効化

デフォルトでは、すべてのリクエスト URI がデコードされます。そのため、URI /monster/night%20stalker と URI /monster/night stalker は同等です。自動 URI デコードを使用すると、ASCII 文字セット以外の文字をパラメーターとして送信しやすくなります。

URI を自動的にデコードしたくない場合は、javax.ws.rs.Encoded アノテーションを使用して URI のデコードを非アクティブ化できます。アノテーションは、以下のレベルで URI のデコードを非アクティブにするために使用できます。

  • クラスレベル - @Encoded アノテーションでクラスをデコードすると、クラス内のすべてのパラメーター、フィールド、および Bean プロパティーの URI デコードが無効になります。
  • メソッドレベル - @Encoded アノテーションでメソッドをデコードすると、クラスのすべてのパラメーターの URI デコードが無効になります。
  • パラメーター/フィールドレベル - パラメーターまたはフィールドを @Encoded アノテーションでデコレートすると、クラスのすべてのパラメーターの URI デコードが無効になります。

例47.5「URI のデコードの無効化」は、getMonster() メソッドが URI デコードを使用しないリソースを示しています。addMonster() メソッドは、type パラメーターの URI デコードのみを無効にします。

例47.5 URI のデコードの無効化

@Path("/monstersforhire/")
public class MonsterService
{
  ...

  @GET
  @Encoded
  @Path("/{type}")
  public Monster getMonster(@PathParam("type") String type,
                            @QueryParam("id") String id)
  {
    ...
  }

  @PUT
  @Path("/{id}")
  public void addMonster(@Encoded @PathParam("type") String type,
                         @QueryParam("id") String id)
  {
    ...
  }
  ...
}

エラー処理

URI インジェクションアノテーションのいずれかを使用してデータを注入しようとすると、元の例外をラップする WebApplicationException 例外が生成されます。WebApplicationException 例外のステータスは 404 に設定されます。

47.2.3. HTTP メッセージヘッダーからのデータの注入

概要

通常、要求メッセージの HTTP ヘッダーとメッセージに関する一般的な情報、送信方法、および予想される応答の詳細を渡します。いくつかの標準ヘッダーが一般的に認識されて使用されていますが、HTTP 仕様では、任意の名前/値ペアを HTTP ヘッダーとして使用できます。JAX-RS API には、HTTP ヘッダー情報をリソース実装に注入する簡単なメカニズムがあります。

最も一般的に使用される HTTP ヘッダーの 1 つがクッキーです。Cookie を使用すると、HTTP クライアントとサーバーが複数の要求/応答シーケンスで静的情報を共有できます。JAX-RS API には、クッキーから直接リソース実装にデータを注入するアノテーションがあります。

HTTP ヘッダーからの情報の注入

javax.ws.rs.HeaderParam アノテーションは、HTTP ヘッダーフィールドのデータをパラメーター、フィールド、または Bean プロパティーに注入するために使用されます。値が抽出され、リソース実装にインジェクトされる HTTP ヘッダーフィールドの名前を指定する単一のパラメーターがあります。関連するパラメーター、フィールド、または Bean プロパティーは、「サポートされるデータタイプ」 で説明されているデータタイプに準拠している必要があります。

If-Modified-Since ヘッダーの挿入 は、HTTP If-Modified-Since ヘッダーの値をクラスの oldestDate フィールドに注入するコードを示しています。

If-Modified-Since ヘッダーの挿入

import javax.ws.rs.HeaderParam;
...
class RecordKeeper
{
  ...
  @HeaderParam("If-Modified-Since")
  String oldestDate;
  ...
}

クッキーからの情報の挿入

クッキーは特別な HTTP ヘッダータイプです。これらは、最初の要求でリソース実装に渡される 1 つ以上の名前と値のペアで設定されます。最初の要求後に、クッキーは各クッキーでプロバイダーとコンシューマーの間を行き来します。コンシューマーだけがリクエストを生成するため、Cookie を変更できます。クッキーは通常、複数の要求/応答シーケンス間でセッションを維持し、ユーザー設定やその他の永続化可能なデータを保存するために使用されます。

javax.ws.rs.CookieParam アノテーションは、クッキーのフィールドから値を抽出し、これをリソース実装に注入します。このアノテーションでは、値が抽出される Cookie のフィールドの名前を指定する単一のパラメーターを使用できます。「サポートされるデータタイプ」に示されているデータ型に加え、@CookieParam が付けられたエンティティーも Cookie オブジェクトになることができます。

例47.6「クッキーの挿入」は、handle クッキーの値を CB クラスのフィールドに注入するためのコードを示しています。

例47.6 クッキーの挿入

import javax.ws.rs.CookieParam;
...
class CB
{
  ...
  @CookieParam("handle")
  String handle;
  ...
}

エラー処理

HTTP メッセージのインジェクションアノテーションのいずれかを使用してデータを注入しようとすると、元の例外をラップする WebApplicationException 例外が生成されます。WebApplicationException 例外のステータスは 400 に設定されます。

47.2.4. HTML フォームからのデータの挿入

概要

HTML フォームでは、ユーザーから情報を簡単に取得する方法で、作成も簡単です。フォームデータは、HTTP GET リクエストおよび HTTP POST リクエストに使用できます。

GET
フォームデータが HTTP GET リクエストの一部として送信されると、データはクエリーパラメーターのセットとして URI に追加されます。クエリーパラメーターからのデータの注入については、「クエリーパラメーターの使用」 で説明します。
POST
フォームデータが HTTP POST の一部として送信されると、データは HTTP メッセージボディーに配置されます。フォームデータは、対象のフォームデータをサポートする通常のエンティティーパラメーターを使用して処理できます。また、@FormParam アノテーションを使用してデータを抽出し、リソースメソッドのパラメーターに注入することによって処理することもできます。

@FormParam アノテーションを使用したフォームデータの挿入

javax.ws.rs.FormParam アノテーションは、フィールド値をフォームデータから抽出し、値をリソースメソッドパラメーターに注入します。このアノテーションでは、値を抽出するフィールドのキーを指定する単一のパラメーターを指定できます。関連するパラメーターは、「サポートされるデータタイプ」 に記載のデータタイプに準拠する必要があります。

重要

JAX-RS API Javadoc には、@FormParam アノテーションをフィールド、メソッド、およびパラメーターに配置できると記載されています。ただし、@FormParam アノテーションは、リソースメソッドパラメーターに配置する場合にのみ意味があります。

リソースメソッドパラメーターへのフォームデータの挿入 は、フォームデータをパラメーターに注入するリソースメソッドを示しています。このメソッドは、クライアントのフォームに文字列データが含まれる titletags、および body の 3 つのフィールドが含まれていることを前提としています。

リソースメソッドパラメーターへのフォームデータの挿入

import javax.ws.rs.FormParam;
import javax.ws.rs.POST;

...
@POST
public boolean updatePost(@FormParam("title") String title,
                          @FormParam("tags") String tags,
                          @FormParam("body") String post)
{
  ...
}

47.2.5. 挿入するデフォルト値の指定

概要

より堅牢なサービス実装を提供するために、任意のパラメーターをデフォルト値に設定することができます。長い URI 文字列を入力するとエラーが発生しやすいため、これはクエリーパラメーターとマトリックスパラメーターから取得される値に特に役立ちます。また、要求側のシステムに適切な情報がないまま、すべての値を使用してクッキーを構築している可能性があるので、クッキーから抽出されたパラメーターにデフォルト値を設定すると良いでしょう。

javax.ws.rs.DefaultValue アノテーションは、以下のインジェクションアノテーションと併用できます。

  • @PathParam
  • @QueryParam
  • @MatrixParam
  • @FormParam
  • @HeaderParam
  • @CookieParam

@DefaultValue アノテーションは、インジェクションアノテーションに対応するデータがリクエストに存在しない場合に利用するデフォルト値を指定します。

構文

パラメーターのデフォルト値を設定するための構文に、@DefaultValue アノテーションを使用するための構文を示します。

パラメーターのデフォルト値を設定するための構文

import javax.ws.rs.DefaultValue;
  ...
  void resourceMethod(@MatrixParam("matrix")
                      @DefaultValue("value)
                      int someValue, ... )
  ...

このアノテーションは、パラメーター、Bean、フィールドの前に配置する必要があります。これは有効になります。付属のインジェクションアノテーションに対する @DefaultValue アノテーションの位置は重要ではありません。

@DefaultValue アノテーションは、単一のパラメーターを取ります。このパラメーターは、インジェクションアノテーションに基づいて適切なデータを抽出できない場合にフィールドに注入される値です。値は、任意の String 値にすることができます。この値は、関連付けられたフィールドのタイプと互換性がある必要があります。たとえば、関連付けられたフィールドが int 型である場合、blue のデフォルト値では例外が発生します。

リストとセットの処理

アノテーション付きのパラメーター、Bean、またはフィールドのタイプが List、Set、または SortedSet の場合に、生成されるコレクションには指定されたデフォルト値から 1 つのエントリーがマッピングされます。

デフォルト値の設定 は、@DefaultValue を使用して値が中ニュされるフィールドのデフォルト値を指定する 2 つの例を示しています。

デフォルト値の設定

import javax.ws.rs.DefaultValue;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/monster")
public class MonsterService
{

  @Get
  public Monster getMonster(@QueryParam("id") @DefaultValue("42") int id,
                            @QueryParam("type") @DefaultValue("bogeyman") String type)
  {
    ...
  }

  ...
}

デフォルト値の設定getMonster() メソッドは、GET リクエストが baseURI/monster に送信されると呼び出されます。メソッドでは、idtype の 2 つのクエリーパラメーターが URI に追加されることが想定されます。そのため、URI baseURI/monster?id=1&type=fomóiri を使用する GET リクエストは 1 の ID で Fomóiri を返します。

@DefaultValue アノテーションは両方のパラメーターに配置されるため、クエリーパラメーターが省略されると getMonster() メソッドが機能できます。baseURI/monster に送信された GET リクエストは、URI baseURI/monster?id=42&type=bogeyman を使用する GET リクエストと同等です。

47.2.6. Java Bean へのパラメーターの挿入

概要

REST 経由で HTML フォームを投稿する場合は、サーバー側で一般的なパターンで Java Bean を作成して、フォームで受け取ったすべてのデータをカプセル化します (場合によっては他のパラメーターや HTML ヘッダーからでもデータもカプセル化します)。通常、この Java Bean の作成は 2 段階のプロセスになります。リソースメソッドはインジェクションによって (たとえば、@FormParam メソッドパラメーターにアノテーションを追加することによって) フォームの値を受け取り、リソースメソッドは Bean のコンストラクタを呼び出し、フォームデータを渡します。

JAX-RS 2.0 @BeanParam アノテーションを使用すると、このパターンを 1 段階で実装できます。フォームデータは bean クラスのフィールドに直接挿入でき、Bean 自体は JAX-RS ランタイムによって自動的に作成されます。これは、例を使用することで最も簡単に説明できます。

挿入ターゲット

@BeanParam アノテーションは、リソースメソッドパラメーター、リソースフィールド、または Bean プロパティーに追加できます。ただし、パラメーターターゲットは、すべてのリソースクラスのライフサイクルで使用できる唯一の種類のターゲットです。他の種類のターゲットは、要求別のライフサイクルに制限されます。この状況は、表47.1「@BeanParam Injection Targets」 にまとめられています。

表47.1 @BeanParam Injection Targets

ターゲットリソースクラスのライフサイクル

PARAMETER

すべて

FIELD

per-request(デフォルト)

METHOD (Bean プロパティー)

per-request(デフォルト)

BeanParam アノテーションのない例

以下の例は、従来のアプローチ (@BeanParam を使用しない) を使用して Java Bean でフォームデータを取得する方法を表しています。

// Java
import javax.ws.rs.POST;
import javax.ws.rs.FormParam;
import javax.ws.rs.core.Response;
...
@POST
public Response orderTable(@FormParam("orderId")  String orderId,
                           @FormParam("color")    String color,
                           @FormParam("quantity") String quantity,
                           @FormParam("price")    String price)
{
    ...
    TableOrder bean = new TableOrder(orderId, color, quantity, price);
    ...
    return Response.ok().build();
}

この例では、orderTable メソッドは家具の Web サイトからある数量のテーブルを注文するために使用されるフォームを処理します。注文フォームが投稿されると、フォームの値は orderTable メソッドのパラメーターに注入され、orderTable メソッドは注入されたフォームデータを使用して TableOrder クラスのインスタンスを明示的に作成します。

BeanParam アノテーションの使用例

上記の例は、@BeanParam アノテーションを利用するためにリファクタリングできます。@BeanParam のアプローチを使用する場合、フォームパラメーターは Bean クラスの TableOrder フィールドに直接注入できます。実際、@PathParam@QueryParam@FormParam@MatrixParam@CookieParam、および @HeaderParam などの、Bean クラスの標準の JAX-RS パラメーターアノテーションを使用できます。フォームを処理するコードは、以下のようにリファクタリングできます。

// Java
import javax.ws.rs.POST;
import javax.ws.rs.FormParam;
import javax.ws.rs.core.Response;
...
public class TableOrder {
    @FormParam("orderId")
    private String orderId;

    @FormParam("color")
    private String color;

    @FormParam("quantity")
    private String quantity;

    @FormParam("price")
    private String price;

    // Define public getter/setter methods
    // (Not shown)
    ...
}
...
@POST
public Response orderTable(@BeanParam TableOrder orderBean)
{
    ...
    // Do whatever you like with the 'orderBean' bean
    ...
    return Response.ok().build();
}

これでフォームアノテーションが Bean クラス TableOrder に追加され、以下のようにリソースメソッドの署名にある @FormParam アノテーションをすべて単一の @BeanParam アノテーションで置き換えることができるようになりました。フォームが orderTable リソースメソッドに投稿されると、JAX-RS ランタイムは TableOrder インスタンス orderBean を自動的に作成し、Bean クラスのパラメーターアノテーションが指定するすべてのデータを注入するようになりました。