46.6. リソースの選択方法
概要
特定の URI を 1 つ以上のリソースメソッドにマップすることが可能です。たとえば、URI customerservice/12/ma は @Path("customerservice/{id}")
または @Path("customerservice/{id}/{state}")
テンプレートと一致する可能性があります。JAX-RS は、要求とリソースメソッドと照合するための照合アルゴリズムを指定します。アルゴリズムは、正規化された URI、HTTP 動詞、および要求エンティティーと応答エンティティーのメディアタイプを、リソースクラスのアノテーションと比較します。
基本的な選択アルゴリズム
JAX-RS 選択アルゴリズムは、次の 3 つの段階に分けられます。
ルートリソースクラスを決定します。
リクエスト URI は
@Path
アノテーションが付けられたすべてのクラスに対して照合されます。@Path
アノテーションがリクエスト URI と一致するクラスが判断されます。リソースクラスの
@Path
アノテーションの値が要求 URI 全体と一致する場合、クラスのメソッドは 3 番目のステージへの入力として使用されます。オブジェクトがリクエストを処理するかどうかを決定します。
リクエスト URI が選択したクラスの
@Path
アノテーションの値より長い場合、リソースメソッドの@Path
アノテーションの値は、要求を処理できるサブリソースの検索に使用されます。1 つ以上のサブリソースメソッドが要求 URI と一致する場合には、これらのメソッドは第 3 ステージの入力として使用されます。
要求 URI に一致するのがサブリソースロケーターのみである場合には、サブリソースロケーターによって作成されたオブジェクトのリソースメソッドは、要求 URI と一致します。この段階は、サブリソースメソッドが要求 URI と一致するまで繰り返されます。
要求を処理するリソースメソッドを選択します。
HTTP 動詞アノテーションが要求の HTTP 動詞と一致するリソースメソッド。さらに、選択されたリソースメソッドは、要求エンティティー本体のメディアタイプを受け入れ、要求で指定されたメディアタイプに準拠する応答を生成できる必要があります。
複数のリソースクラスからの選択
選択アルゴリズムの最初の 2 つの段階では、要求を処理するリソースを決定します。場合によっては、リソースはリソースクラスで実装されます。それ以外の場合は、同じ URI テンプレートを使用する 1 つ以上のサブリソースで実装されます。要求 URI に一致するリソースが複数ある場合には、サブリソースよりもリソースクラスが優先されます。
リソースクラスとサブリソースを並べ替えた後も複数のリソースが要求 URI に一致する場合は、次の基準を使用して単一のリソースを選択します。
URI テンプレートで最もリテラル文字が多いリソースを優先します。
リテラル文字は、テンプレート変数の一部ではない文字です。たとえば、/widgets/{id}/{color} には 10 個のリテラル文字があり、/widgets/1/{color} には 11 個のリテラル文字があります。したがって、リクエスト URI /widgets/1/red は、URI テンプレートとして /widgets/1/{color} を使用してリソースと照合されます。
注記末尾のスラッシュ (
/
) はリテラル文字としてカウントされます。したがって、/joefred/ は /joefred よりも優先されます。URI テンプレートで変数が最も多いリソースを優先します。
要求 URI /widgets/30/green は、/widgets/{id}/{color} と /widgets/{amount}/ の両方と一致する可能性があります。ただし、変数が 2 つあるため、URI テンプレート /widgets/{id}/{color} のリソースが選択されます。
変数が最も多く、正規表現が含まれるリソースを優先します。
要求 URI /widgets/30/green は、/widgets/{number}/{color} と /widgets/{id:.}/{color}* の両方と一致する可能性があります。ただし、正規表現を含む変数があるため、URI テンプレート */widgets/{id:.}/{color} を含むリソースが選択されます。
複数のリソースメソッドからの選択
多くの場合に、要求 URI に一致するリソースを選択すると、要求を処理できるリソースメソッドが 1 つになります。メソッドは、要求で指定された HTTP 動詞をリソースメソッドの HTTP 動詞アノテーションと照合することによって決定されます。適切な HTTP 動詞アノテーションが存在することに加えて、選択されたメソッドは、要求内の要求エンティティーを処理でき、要求のメタデータで指定された適切なタイプの応答を生成できなければなりません。
リソースメソッドが処理できるリクエストエンティティーの型は @Consumes
アノテーションによって指定されます。リソースメソッドが生成できる応答の型は @Produces
アノテーションを使用して指定されます。
リソースを選択すると、要求を処理できる複数のメソッドが生成されます。次の基準を使用して、要求を処理するリソースメソッドを選択します。
- サブリソースよりもリソースメソッドを優先します。
- サブリソースロケーターよりもサブリソースメソッドを優先します。
@Consumes
アノテーションと@Produces
アノテーションで最も具体的な値を使用するメソッドを優先します。たとえば、アノテーション
@Consumes("text/xml")
を持つメソッドは、アノテーション@Consumes("text/*")
を持つメソッドよりも優先されます。どちらのメソッドも、@Consumes
アノテーションのないメソッドやアノテーション@Consumes("\*/*")
よりも優先されます。リクエスト本文エンティティーのコンテンツタイプに最も近いメソッドを優先します。
注記リクエストボディーエンティティーのコンテンツ型は HTTP
Content-Type
プロパティーで指定されます。応答として受け入れられるコンテンツタイプに最も近い方法を優先します。
注記レスポンスとして受け入れられるコンテンツタイプは、HTTP
Accept
プロパティーで指定されます。
選択プロセスのカスタマイズ
開発者からの報告によると、このアルゴリズムでは、複数のリソースクラスを選択する方法に何らかの制限がある場合があります。たとえば、特定のリソースクラスが一致し、このクラスに一致するリソースメソッドがない場合に、このアルゴリズムは実行を停止します。一致していても残りのリソースクラスはチェックされません。
Apache CXF には、org.apache.cxf.jaxrs.ext.ResourceComparator インターフェイスが含まれており、ランタイムが複数の一致するリソースクラスの処理方法のカスタマイズに使用できます。例46.9「リソース選択をカスタマイズするためのインターフェイス」 に示される ResourceComparator インターフェイスには、実装する必要のあるメソッドが 2 つあります。1 つは 2 つのリソースクラスを、もう 1 つは 2 つのリソースメソッドを比較します。
例46.9 リソース選択をカスタマイズするためのインターフェイス
package org.apache.cxf.jaxrs.ext; import org.apache.cxf.jaxrs.model.ClassResourceInfo; import org.apache.cxf.jaxrs.model.OperationResourceInfo; import org.apache.cxf.message.Message; public interface ResourceComparator { int compare(ClassResourceInfo cri1, ClassResourceInfo cri2, Message message); int compare(OperationResourceInfo oper1, OperationResourceInfo oper2, Message message); }
カスタム実装は、次のように 2 つのリソースから選択します。
-
最初のパラメーターが 2 番目のパラメーターよりも一致している場合は、
1
を返します。 -
2 番目のパラメーターが最初のパラメーターよりも一致している場合は、
-1
を返します。
0
が返されると、ランタイムはデフォルトの選択アルゴリズムで続行されます。
カスタム ResourceComparator 実装を登録するには、子の resourceComparator
をサービスの jaxrs:server
要素に追加します。