Java™ API for RESTful
Web Services (JAX-RS) を使用すると、開発者はカスタム・エンティティー・プロバイダーを
アプリケーションに追加できます。着信要求メッセージ本体や
発信応答メッセージ本体を Java 型で表したい場合、
カスタム・エンティティー・プロバイダーを使用してください。カスタム・エンティティー・プロバイダーを追加することにより、
カスタムの Java 型をメッセージ本体から非直列化することができ、任意のメディア・タイプをメッセージ本体として
直列化することができます。
このタスクについて
カスタム・エンティティー・プロバイダーは、
クラスに javax.ws.rs.ext.Provider アノテーションを付けることで作成されます。このクラス
は javax.ws.rs.ext.MessageBodyReader インターフェースまたは javax.ws.rs.ext.MessageBodyWriter インターフェース、
あるいは両方のインターフェースを実装しなければなりません。javax.ws.rs.core.Application サブクラス getClasses() メソッドで戻されるクラスのリストに、
このプロバイダー・クラスを追加する必要があります。
手順
- カスタム・エンティティー・プロバイダーにする新しい Java クラスを
作成します。 この手順で
示されるコード例は、com.ibm.json.java.JSONObject タイプ用のリーダーとライター
を作成して、com.ibm.json.java.JSONObject タイプを着信要求エンティティー・パラメーターとして、また、
応答エンティティーを含むための戻りの型として使用できるようにします。
public class MyEntityProvider {
}
- @javax.ws.rs.ext.Provider アノテーションを追加します。 このアノテーションを追加すること
によって、このクラスが JAX-RS プロバイダーであることが JAX-RS ランタイム環境に対して
示されます。この Provider アノテーションが指定されていないと、
ランタイム環境はこのクラスがカスタム・プロバイダーであることを検出
しません。
@javax.ws.rs.ext.Provider
public class MyEntityProvider {
}
- (オプション) エンティティー・プロバイダーがサポートするメディア・タイプを制限する場合は、@javax.ws.rs.Consumes アノテーションまたは @javax.ws.rs.Produces アノテーション
を追加します。 以下のコード・スニペットでは、プロバイダーが起動されるのは、
着信コンテンツ・タイプまたは発信コンテンツ・タイプ
が application/json の場合のみです。
@javax.ws.rs.ext.Provider
@javax.ws.rs.Consumes("application/json")
@javax.ws.rs.Produces("application/json")
public class MyEntityProvider {
}
- エンティティー・プロバイダーがメッセージ本体を非直列化する必要がある場合、javax.ws.rs.ext.MessageBodyReader<T> を
実装します。
汎用タイプ <T> を使用して、
エンティティー・プロバイダーがサポートするタイプを制限できます。
メッセージ本体リーダーを javax.ws.rs.ext.MessageBodyReader<com.ibm.json.java.JSONObject> と
定義することによって、生成されるのは com.ibm.json.java.JSONObject オブジェクトのみ
であることを JAX-RS ランタイム環境が認識します。
エンティティー・プロバイダーがサポートする必要のあるタイプのセットが複雑な場合は、
javax.ws.rs.ext.MessageBodyReader<Object> の実装を検討してください。
@javax.ws.rs.ext.Provider
@javax.ws.rs.Consumes("application/json")
@javax.ws.rs.Produces("application/json")
public class MyEntityProvider implements
javax.ws.rs.ext.MessageBodyReader<com.ibm.json.java.JSONObject> {
public boolean isReadable(Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return com.ibm.json.java.JSONObject.class == type;
}
public com.ibm.json.java.JSONObject readFrom(Class<com.ibm.json.java.JSONObject> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
/* This InputStream reads from the entityStream and constructs the object. */
com.ibm.json.java.JSONObject retObj = com.ibm.json.java.JSONObject.parse(entityStream);
return retObj;
}
}
- エンティティー・プロバイダーがメッセージ本体を直列化する必要がある場合、javax.ws.rs.ext.MessageBodyWriter<T> を
実装します。 MessageBodyReader<T> インターフェースと MessageBodyWriter<T> インターフェース
を同じ Java クラスで実装することができます。
以下のコード・スニペットでは、MessageBodyWriter 実装のみが示されています。
@Provider
public class MyEntityProvider implements
MessageBodyWriter<Object> {
public long getSize(Object t,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
/* return -1 if the content length cannot be determined */
return -1;
}
public boolean isWriteable(Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return MyType.class == type;
}
public void writeTo(Object t,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
entityStream.write(MyType.getBytes());
}
}
- カスタム・エンティティー・プロバイダーを javax.ws.rs.core.Application サブクラス
に追加し、getClasses() メソッドから戻されるクラスのセットに追加
します。 複数のカスタム・エンティティー・プロバイダーを、戻されるクラスのセットに
追加することができます。
public class MyApplication extends javax.ws.rs.core.Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyEntityProvider.class);
return classes;
}
}
タスクの結果
これで、カスタム・エンティティー・プロバイダーが定義され、そのプロバイダーが JAX-RS Web アプリケーションに追加されました。
トラブルの回避 (Avoid trouble): 以下のヒントを使用して、カスタム・エンティティー・フォーマットを実装するときの
一般的なエラーを解決します。
- カスタム・プロバイダーが見つからない。
この問題を解決するには、次のアクションを実行します。
- プロバイダーに @javax.ws.rs.ext.Provider アノテーションが付いていることを確認します。
このアノテーションが付いていないクラスは、プロバイダーとして登録されません。
- javax.ws.rs.core.Application クラスのサブクラスに対する getClasses() メソッドから戻されるクラスのセットに、プロバイダーが
追加されていることを確認します。
- プロバイダー・クラスの @javax.ws.rs.Produces 値または @javax.ws.rs.Consumes 値が
正しいことを確認します。
- javax.ws.rs.ext.MessageBodyReader#isReadable メソッド
または javax.ws.rs.ext.MessageBodyWriter#isWritable メソッドが正しく実装されていて、
これらのメソッドが使用されたときに値 true が正しく戻される
ことを確認します。
- カスタム MessageBodyWriter エンティティー・プロバイダーのヘッダーまたは出力
が正しくない。
この問題を解決するには、次のアクションを実行します。
- javax.ws.rs.ext.MessageBodyWriter#getSize での応答のサイズが、
サイズが不明な場合に -1 に設定されているか、
または、サイズが判明している場合に正しいサイズに設定されていることを確認します。このサイズ値が不正確な場合、クライアント
が応答を切り捨てる可能性があります。
- javax.ws.rs.ext.MessageBodyWriter#writeTo メソッドに HTTP ヘッダーが設定される
場合、HTTP 応答の残りが送信される前にヘッダーを設定する
必要があります。HTTP ヘッダーは応答の先頭で送信されます。したがって、
ヘッダーを設定するのが、メイン応答メッセージ本体のクライアントへの送信が開始された後になった
場合は、応答ヘッダーを送信するのには遅すぎるタイミングです。
gotcha