61.7. エンティティーライターインターセプター
概要
本セクションでは、エンティティーライターインターセプター を実装し、登録する方法を説明します。これにより、クライアント側またはサーバー側でメッセージボディーを書き込む際に出力ストリームをインターセプトできます。これは通常、暗号化や復号などの要求ボディーの汎用的な変換や圧縮や圧縮解除に役立ちます。
WriterInterceptor インターフェイス
javax.ws.rs.ext.WriterInterceptor インターフェイスは以下のように定義されます。
// Java
...
package javax.ws.rs.ext;
public interface WriterInterceptor {
void aroundWriteTo(WriterInterceptorContext context)
throws java.io.IOException, javax.ws.rs.WebApplicationException;
}
WriterInterceptor インターフェイスを実装することで、メッセージボディー (Entity オブジェクト) をサーバー側またはクライアント側で書き込む際にインターセプトできます。エンティティーライターインターセプターは、以下のいずれかのコンテキストで使用できます。
- サーバー側: サーバー側のインターセプターとしてバインドされた場合に、エンティティーライターインターセプターは、マーシャリングされ、クライアントに送信される直前に応答メッセージボディーをインターセプトします。
- クライアント側: クライアント側のインターセプターとしてバインドされた場合に、エンティティーライターインターセプターは、マーシャリングされてサーバーに送信される直前に要求メッセージのボディーをインターセプトします。
WriterInterceptorContext インターフェイス
WriterInterceptor の aroundWriteTo メソッドは、メッセージボディー (Entity オブジェクト) とメッセージメタデータの両方にアクセスするために使用できる javax.ws.rs.ext.WriterInterceptorContext 型の引数を 1 つ受け取ります。
WriterInterceptorContext インターフェイスは以下のように定義されます。
// Java
...
package javax.ws.rs.ext;
import java.io.IOException;
import java.io.OutputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap;
public interface WriterInterceptorContext extends InterceptorContext {
void proceed() throws IOException, WebApplicationException;
Object getEntity();
void setEntity(Object entity);
OutputStream getOutputStream();
public void setOutputStream(OutputStream os);
MultivaluedMap<String, Object> getHeaders();
}InterceptorContext インターフェイス
WriterInterceptorContext インターフェイスは、ベース InterceptorContext インターフェイスから継承されたメソッドもサポートします。InterceptorContext の定義については、「InterceptorContext インターフェイス」を参照してください。
クライアント側での実装例
クライアント側にエンティティーライターインターセプターを実装するには、WriterInterceptor インターフェイスを実装するクラスを定義します。
たとえば、以下のコードは、クライアント側 (優先度が 10) のエンティティーライターインターセプターの例を示しています。これは、送信リクエストのメッセージボディーにテキストの行を余分に追加します。
// Java
package org.jboss.fuse.example;
import java.io.IOException;
import java.io.OutputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
import javax.annotation.Priority;
@Priority(value = 10)
public class SampleClientWriterInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext interceptorContext)
throws IOException, WebApplicationException {
OutputStream outputStream = interceptorContext.getOutputStream();
String appendedContent = "\nInterceptors always get the last word in.";
outputStream.write(appendedContent.getBytes());
interceptorContext.setOutputStream(outputStream);
interceptorContext.proceed();
}
}サーバー側での実装例
サーバー側のエンティティーライターインターセプターを実装するには、WriterInterceptor インターフェイスを実装し、@Provider アノテーションを付けるクラスを定義します。
たとえば、以下のコードは、サーバー側 (優先度が 10) のエンティティーライターインターセプターの例を示しています。これは、送信要求のメッセージボディーにテキストの行を余分に追加します。
// Java
package org.jboss.fuse.example;
import java.io.IOException;
import java.io.OutputStream;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
import javax.annotation.Priority;
@Priority(value = 10)
@Provider
public class SampleServerWriterInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext interceptorContext)
throws IOException, WebApplicationException {
OutputStream outputStream = interceptorContext.getOutputStream();
String appendedContent = "\nInterceptors always get the last word in.";
outputStream.write(appendedContent.getBytes());
interceptorContext.setOutputStream(outputStream);
interceptorContext.proceed();
}
}クライアント側のライターインターセプターのバインド
JAX-RS 2.0 クライアント API を使用すると、エンティティーライターインターセプターを javax.ws.rs.client.Client オブジェクトまたは javax.ws.rs.client.WebTarget オブジェクトに直接登録できます。実質的に、ライターインターセプターはオプションで異なるスコープに適用できるため、インターセプターの影響を受けるのは、特定の URI パスのみです。
たとえば、以下のコードは、client オブジェクトを使用して実行されたすべての呼び出しに適用されるように SampleClientReaderInterceptor インターセプターを登録する方法を示しています。
// Java ... import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; ... Client client = ClientBuilder.newClient(); client.register(SampleClientReaderInterceptor.class);
JAX-RS 2.0 クライアントでインターセプターを登録する方法は、「クライアントエンドポイントの設定」 を参照してください。
サーバー側でのライターインターセプターのバインド
サーバー側でライターインターセプターを バインド する (Apache CXF ランタイムにインストールする) には、以下の手順を実行します。
以下のコードフラグメントで示されるように、
@Providerアノテーションをライターインターセプタークラスに追加します。// Java package org.jboss.fuse.example; ... import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) @Provider public class SampleServerWriterInterceptor implements WriterInterceptor { ... }
ライターインターセプター実装が Apache CXF ランタイムにロードされると、REST 実装はロードされたクラスを自動的にスキャンし、
@Providerアノテーション (スキャンフェーズ) の付いたクラスを検索します。XML で JAX-RS サーバーエンドポイントを定義する場合 (例: 「JAX-RS サーバーエンドポイントの設定」)、
jaxrs:providers要素のプロバイダーリストにライターインターセプターを追加します。<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="interceptorProvider" /> </jaxrs:providers> <bean id="interceptorProvider" class="org.jboss.fuse.example.SampleServerWriterInterceptor"/> </jaxrs:server> </blueprint>注記この手順は、Apache CXF の非標準要件です。厳密に言うと、JAX-RS 標準によれば、インターセプターをバインドするために必要なのは
@Providerアノテーションのみです。しかし実際には、標準的なアプローチはやや柔軟性がなく、大規模なプロジェクトに多くのライブラリーが含まれている場合は、プロバイダーの衝突につながる可能性があります。