Menu Close
50.4. 例外のレスポンスへのマッピング
概要
WebApplicationException 例外をスローすることが現実的でない場合や不可能な場合があります。たとえば、可能なすべての例外をキャッチし、その例外に対して WebApplicationException を作成したくない場合があります。また、アプリケーションコードとの作業を簡単にするカスタム例外を使用したいこともあります。
このようなケースを処理するために、JAX-RS API では、クライアントに送信する Response
オブジェクトを生成するカスタム例外プロバイダーを実装できます。カスタム例外プロバイダーは、ExceptionMapper<E> インターフェースを実装して作成されます。Apache CXF ランタイムで登録されると、型 E
の例外がスローされるたびにカスタムプロバイダーが使用されます。
例外マッパーの選択方法
例外マッパーは 2 つのケースで使用されます。
- 例外またはそのサブクラスの 1 つがスローされると、ランタイムによって適切な例外マッパーがチェックされます。例外マッパーは、スローされた特定の例外を処理する場合に選択されます。スローされた特定の例外に対する例外マッパーがない場合、その例外の最も近いスーパークラスの例外マッパーが選択されます。
デフォルトでは、WebApplicationException はデフォルトマッパー
WebApplicationExceptionMapper
によって処理されます。WebApplicationException 例外を処理する可能性がある追加のカスタムマッパーが登録されていても (カスタムRuntimeException
マッパーなど)、カスタムマッパーは使用されず、代わりにWebApplicationExceptionMapper
が使用されます。ただし、この動作は
Message
オブジェクトのdefault.wae.mapper.least.specific
プロパティーをtrue
に設定して変更できます。このオプションを有効にすると、カスタム例外マッパーを使用して WebApplicationException 例外を処理できるようにするため、デフォルトのWebApplicationExceptionMapper
の優先順位は最低になります。たとえば、このオプションが有効な場合に、カスタムRuntimeException
マッパーを登録することで WebApplicationException 例外をキャッチできます。「WebApplicationException の例外マッパーの登録」 を参照してください。
例外に対して例外マッパーが見つからない場合、例外は ServletException 例外にラップされ、コンテナーランタイムに渡されます。その後、コンテナーランタイムは例外の処理方法を決定します。
例外マッパーの実装
例外マッパーは、javax.ws.rs.ext.ExceptionMapper<E> インターフェースを実装して作成されます。例50.5「例外マッパーインターフェース」 で示されているように、インターフェースには単一のメソッド toResponse()
があります。これは元の例外をパラメーターとして取り、Response
オブジェクトを返します。
例50.5 例外マッパーインターフェース
public interface ExceptionMapper<E extends java.lang.Throwable> { public Response toResponse(E exception); }
例外マッパーによって作成された Response
オブジェクトは、他の Response
オブジェクトのようにランタイムによって処理されます。コンシューマーへの結果となる応答には、Response
オブジェクトにカプセル化されたステータス、ヘッダー、およびエンティティーボディーが含まれます。
例外マッパーの実装はランタイムによってプロバイダーと見なされます。そのため、@Provider
アノテーションを付ける必要があります。
例外マッパーによる Response
オブジェクトの構築中に例外が発生すると、ランタイムは 500 Server Error
のステータスで応答をコンシューマーに送信します。
例50.6「例外から応答へのマッピング」 は、Spring AccessDeniedException 例外を遮断し、403 Forbidden
ステータスと空のエンティティーボディーで応答を生成する例外マッパーを示しています。
例50.6 例外から応答へのマッピング
import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import org.springframework.security.AccessDeniedException; @Provider public class SecurityExceptionMapper implements ExceptionMapper<AccessDeniedException> { public Response toResponse(AccessDeniedException exception) { return Response.status(Response.Status.FORBIDDEN).build(); } }
ランタイムは AccessDeniedException 例外をキャッチし、空のエンティティーボディーと 403
のステータスで Response
オブジェクトを作成します。ランタイムは、通常のレスポンスの場合と同様に Response
オブジェクトを処理します。その結果、コンシューマーはステータスが 403
の HTTP 応答を受信します。
例外マッパーの登録
JAX-RS アプリケーションが例外マッパーを使用できるようにするには、例外マッパーをランタイムで登録する必要があります。例外マッパーは、アプリケーションの設定ファイルの jaxrs:providers
要素を使用してランタイムで登録されます。
jaxrs:providers
要素は jaxrs:server
要素の子で、bean
要素の一覧が含まれます。各 bean
要素は 1 つの例外マッパーを定義します。
例50.7「ランタイムを使用した例外マッパーの登録」 は、カスタム例外マッパー SecurityExceptionMapper
を使用するように設定された JAX-RS サーバーを示しています。
例50.7 ランタイムを使用した例外マッパーの登録
<beans ...> <jaxrs:server id="customerService" address="/"> ... <jaxrs:providers> <bean id="securityException" class="com.bar.providers.SecurityExceptionMapper"/> </jaxrs:providers> </jaxrs:server> </beans>
WebApplicationException の例外マッパーの登録
WebApplicationException
例外の例外マッパーを登録することは、この例外型はデフォルトの WebApplicationExceptionMapper
によって自動的に処理されるため、特殊なケースです。通常、WebApplicationException
を処理する予定のカスタムマッパーを登録する場合でも、引き続きデフォルトの WebApplicationExceptionMapper
によって処理されます。このデフォルトの動作を変更するには、default.wae.mapper.least.specific
プロパティーを true
に設定する必要があります。
たとえば、以下の XML コードは JAX-RS エンドポイントで default.wae.mapper.least.specific
プロパティーを有効にする方法を示しています。
<beans ...> <jaxrs:server id="customerService" address="/"> ... <jaxrs:providers> <bean id="securityException" class="com.bar.providers.SecurityExceptionMapper"/> </jaxrs:providers> <jaxrs:properties> <entry key="default.wae.mapper.least.specific" value="true"/> </jaxrs:properties> </jaxrs:server> </beans>
以下の例のように、インターセプターで default.wae.mapper.least.specific
プロパティーを設定することもできます。
// Java public void handleMessage(Message message) { m.put("default.wae.mapper.least.specific", true); ...