2.7. コンテンツマーシャリングおよびプロバイダー
2.7.1. デフォルトのプロバイダーとデフォルトの Jakarta RESTful Web サービスのコンテンツ リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy は、いくつかの異なるメッセージ本文を自動的にマーシャリングおよびマーシャリング解除できます。
| メディアタイプ | Java タイプ |
|---|---|
|
| Jakarta XML Binding アノテーションが付けられたクラス |
|
| org.w3c.dom.Document |
| * / * | java.lang.String |
| * / * | java.io.InputStream |
|
| プリミティブ、java.lang.String、または String コンストラクターを持つタイプ、または入力用の静的 valueOf(String) メソ背戸、出力用の toOf() メソッド。 |
| * / * | javax.activation.DataSource |
| * / * | java.io.File |
| * / * | byte |
|
| javax.ws.rs.core.MultivaluedMap |
2.7.1.1. テキストメディアタイプおよび文字セット リンクのコピーリンクがクリップボードにコピーされました!
Jakarta RESTful Web Services 仕様に従い、実装は応答の書き込み時にアプリケーション提供の文字セットメタデータに準拠する必要があります。文字セットがアプリケーションによって指定されていない場合、またはサポートされていない文字セットをアプリケーションが指定する場合は、実装で UTF-8 文字セットを使用する必要があります。
反対に、HTTP 仕様によると、送信者が明示的な charset パラメーターを提供しない場合、HTTP 経由で受信すると text タイプのメディアサブタイプは、デフォルトの charset の値である ISO-8859-1 を持つように定義されます。ISO-8859-1 以外の文字セットまたはそのサブセットのデータは、適切な文字セット値でラベル付けする必要があります。
リソースまたはリソースメソッドで指定された文字セットがない場合、RESTEasy は UTF-8 をテキストメディアタイプの文字セットとして使用します。これを行うため、RESTEasy は明示的な charset パラメーターを content-type 応答ヘッダーに追加します。
テキストメディアタイプに UTF-8 が使用されますが、明示的な charset パラメーターが追加されない場合は、コンテキストパラメーター resteasy.add.charset を false に設定します。このパラメーターのデフォルト値は true です。
以下は、テキストメディアタイプです。
-
タイプ
textと任意のサブタイプを含むメディアタイプ -
タイプ
applicationを持つメディアタイプ、xmlで始まるサブタイプ。これには、application/xml-external-parsed-entityおよびapplication/xml-dtdが含まれます。
2.7.2. @Provider クラスを使用したコンテンツマーシャルリング リンクのコピーリンクがクリップボードにコピーされました!
Jakarta RESTful Web Services 仕様を使用すると、独自のリクエスト/レスポンスボディーリーダーおよびライターをプラグインできます。そのためには、クラスに @Provider アノテーションを付け、ライターに @Produces を指定し、リーダーに @Consumes タイプを指定します。MessageBodyReader/Writer インターフェイスも実装する必要があります。
@Provider を使用してアノテーションが付けられたクライアントプロバイダーは、Jakarta RESTful Web Services コンテナーランタイムがアノテーションを処理するためにすべてのクライアントインスタンスに登録する必要があります。不要または重複したクライアントプロバイダー登録の問題を回避するために、システムプロパティー resteasy.client.providers.annotations.disabled は、@Provider アノテーションが付けられたクライアントプロバイダーのデフォルトの処理を無効にます。
RESTEasy ServletContextLoader は自動的に、@Provider アノテーションが付けられたクラスの WEB-INF/lib およびクラスディレクトリーを自動的にスキャンします。または、web.xml ファイルで手動で設定することができます。
2.7.3. Providers ユーティリティークラス リンクのコピーリンクがクリップボードにコピーされました!
javax.ws.rs.ext.Providers は、MessageBodyReaders、Writers、ContextResolvers、ExceptionMappers を検索できるようにする単純なインジェクト可能なインターフェイスです。これは、他のランダムなコンテンツタイプを埋め込みする multipart プロバイダーおよびコンテンツタイプの実装に非常に便利です。
public interface Providers {
<T> MessageBodyReader<T> getMessageBodyReader(Class<T> type, Type genericType, Annotation annotations[], MediaType mediaType);
<T> MessageBodyWriter<T> getMessageBodyWriter(Class<T> type, Type genericType, Annotation annotations[], MediaType mediaType);
<T extends="" throwable=""> ExceptionMapper<T> getExceptionMapper(Class<T> type);
<T> ContextResolver<T> getContextResolver(Class<T> contextType, MediaType mediaType);
}
Providers インスタンスは MessageBodyReader または Writers にインジェクトできます。
@Provider
@Consumes("multipart/fixed")
public class MultipartProvider implements MessageBodyReader {
private @Context Providers providers;
...
}
2.7.4. ドキュメントマーシャリングの設定 リンクのコピーリンクがクリップボードにコピーされました!
XML ドキュメントパーサーは XXE (XML eXternal Entity) 攻撃と呼ばれる攻撃の形式に依存し、外部エンティティーを拡張すると安全でないファイルが読み込まれます。たとえば、次のドキュメントでは、/etc/passwd ファイルが読み込まれる可能性があります。
<!--?xml version="1.0"?-->
<!DOCTYPE foo
[<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<search>
<user>bill</user>
<file>&xxe;<file>
</search>
デフォルトでは、org.w3c.dom.Document ドキュメントの RESTEasy ビルドインアンマーシャルは外部エンティティーを拡張しません。それらは空の文字列に置き換えられます。これは、外部エンティティーを DTD で定義された値に置き換えるように設定できます。そのためには web.xml ファイルで resteasy.document.expand.entity.references コンテキストパラメーターを true に設定します。
例: resteasy.document.expand.entity.references コンテキストパラメーターの設定
<context-param>
<param-name>resteasy.document.expand.entity.references</param-name>
<param-value>true</param-value>
</context-param>
この問題に対処するもう 1 つの方法として、RESTEasy がデフォルトで行う DTD を禁止します。この動作を変更するには、resteasy.document.secure.disableDTDs コンテキストパラメーターを false に設定します。
例: resteasy.document.secure.disableDTDs コンテキストパラメーターの設定
<context-param>
<param-name>resteasy.document.secure.disableDTDs</param-name>
<param-value>false</param-value>
</context-param>
ドキュメントは、バッファーが大規模なエンティティーやあまりにも多くの属性によって引き継がれる場合にドス攻撃の対象となります。たとえば、以下のエンティティーを定義すると、&foo6; の拡張が 1,000,000 foos になります。
<!--ENTITY foo 'foo'-->
<!--ENTITY foo1 '&foo;&foo;&foo;&foo;&foo;&foo;&foo;&foo;&foo;&foo;'-->
<!--ENTITY foo2 '&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;&foo1;'-->
<!--ENTITY foo3 '&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;&foo2;'-->
<!--ENTITY foo4 '&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;&foo3;'-->
<!--ENTITY foo5 '&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;&foo4;'-->
<!--ENTITY foo6 '&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;&foo5;'-->
デフォルトでは、RESTEasy は展開の数とエンティティーごとの属性数を制限します。正確な動作は、基礎となるパーサーによって異なります。この制限を無効にするには、resteasy.document.secure.processing.feature コンテキストパラメーターを false に設定します。
例: resteasy.document.secure.processing.feature コンテキストパラメーターの設定
<context-param>
<param-name>resteasy.document.secure.processing.feature</param-name>
<param-value>false</param-value>
</context-param>
2.7.5. MapProvider の使用 リンクのコピーリンクがクリップボードにコピーされました!
MapProvider を使用して、Jakarta RESTful Web Services リソースでマップを受け入れて返すことができます。
例: マップを許可して返すリソース
@Path("manipulateMap")
@POST
@Consumes("application/x-www-form-urlencoded")
@Produces("application/x-www-form-urlencoded")
public MultivaluedMap<String, String> manipulateMap(MultivaluedMap<String, String> map) {
//do something
return map;
}
クライアントを使用して Jakarta RESTful Web Services リソースへのマッピングを送受信することもできます。
例: クライアント
MultivaluedMap<String, String> map = new MultivaluedHashMap<String, String>();
//add values to the map...
Response response = client.target(generateURL("/manipulateMap"))
.request(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.post(Entity.entity(map, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
String data = response.readEntity(String.class);
//handle data...
2.7.6. 文字列ベースのアノテーションのオブジェクトへの変換 リンクのコピーリンクがクリップボードにコピーされました!
@QueryParam、@MatrixParam、@HeaderParam、@PathParam、および @FormParam などの Jakarta RESTful Web Services の @*Param アノテーションは、raw HTTP 要求で文字列として表されます。これらのタイプのインジェクトされたパラメーターは、それらのオブジェクトに valueOf(String) 静的メソッドまたは String パラメーターを取るコンストラクターがある場合に、オブジェクトに変換できます。
valueOf() メソッドまたは文字列コンストラクターが存在しないクラスがある場合、または HTTP リクエストに不適切な場合、Jakarta RESTful Web Services は javax.ws.rs.ext.ParamConverterProvider および javax.ws.rs.ext.ParamConverter を提供し、メッセージパラメーター値を対応するカスタム Java タイプに変換します。ParamConverterProvider は、プログラムを用いて Jakarta RESTful Web Services ランタイムに登録されるか、プロバイダースキャンフェーズで Jakarta RESTful Web Services ランタイムによって自動的に検出されるよう @Provider アノテーションを付ける必要があります。
たとえば、以下の手順では、カスタム pos オブジェクトを作成する方法を示します。@QueryParam、@PathParam、@MatrixParam、@HeaderParam などのメッセージパラメーターから POJO オブジェクトへの変換は、ParamConverter インターフェイスおよび ParamConverterProvider インターフェイスの実装によって実行されます。
カスタム POJO クラスを作成します。
public class POJO { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }カスタム POJO Converter クラスを作成します。
public class POJOConverter implements ParamConverter<POJO> { public POJO fromString(String str) { System.out.println("FROM STRNG: " + str); POJO pojo = new POJO(); pojo.setName(str); return pojo; } public String toString(POJO value) { return value.getName(); } }カスタム POJO Converter Provider クラスを作成します。
public class POJOConverterProvider implements ParamConverterProvider { @Override public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { if (!POJO.class.equals(rawType)) return null; return (ParamConverter<T>)new POJOConverter(); } }カスタム MyResource クラスを作成します。
@Path("/") public class MyResource { @Path("{pojo}") @PUT public void put(@QueryParam("pojo") POJO q, @PathParam("pojo") POJO pp, @MatrixParam("pojo") POJO mp, @HeaderParam("pojo") POJO hp) { ... } }
ParamConverter の機能の拡張
Jakarta RESTful Web Services セマンティクスでは、ParamConverter は個別のオブジェクトを表す単一の文字列を変換します。RESTEasy はセマンティックを拡張して、ParamConverter が複数オブジェクトの文字列表現を解析できるようにし、List<T>、Set<T>、SortedSet<T>、array、またはその他の複数値のデータ構造の生成を可能にします。
たとえば、以下のリソースについて見てみましょう。
@Path("queryParam")
public static class TestResource {
@GET
@Path("")
public Response conversion(@QueryParam("q") List<String> list) {
return Response.ok(stringify(list)).build();
}
}
private static <T> String stringify(List<T> list) {
StringBuffer sb = new StringBuffer();
for (T s : list) {
sb.append(s).append(',');
}
return sb.toString();
}
以下のように、標準の表記を使用して TestResource を呼び出します。
@Test
public void testQueryParamStandard() throws Exception {
ResteasyClient client = new ResteasyClientBuilder().build();
Invocation.Builder request = client.target("http://localhost:8081/queryParam?q=20161217&q=20161218&q=20161219").request();
Response response = request.get();
System.out.println("response: " + response.readEntity(String.class));
}
結果: response: 20161217,20161218,20161219,.
代わりにコンマ区切りの表記を使用する場合は、以下を追加できます。
public static class MultiValuedParamConverterProvider implements ParamConverterProvider
@SuppressWarnings("unchecked")
@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
if (List.class.isAssignableFrom(rawType)) {
return (ParamConverter<T>) new MultiValuedParamConverter();
}
return null;
}
}
public static class MultiValuedParamConverter implements ParamConverter<List<?>> {
@Override
public List<?> fromString(String param) {
if (param == null || param.trim().isEmpty()) {
return null;
}
return parse(param.split(","));
}
@Override
public String toString(List<?> list) {
if (list == null || list.isEmpty()) {
return null;
}
return stringify(list);
}
private static List<String> parse(String[] params) {
List<String> list = new ArrayList<String>();
for (String param : params) {
list.add(param);
}
return list;
}
}
これで、以下のように TestResource を呼び出すことができます。
@Test
public void testQueryParamCustom() throws Exception {
ResteasyClient client = new ResteasyClientBuilder().build();
Invocation.Builder request = client.target("http://localhost:8081/queryParam?q=20161217,20161218,20161219").request();
Response response = request.get();
System.out.println("response: " + response.readEntity(String.class));
}
取得: : 20161217,20161218,20161219,
この場合では、MultiValuedParamConverter.fromString() 関数は ArrayList を作成して返すため、TestResource.conversion() 関数を書き換えることができます。
@Path("queryParam")
public static class TestResource {
@GET
@Path("")
public Response conversion(@QueryParam("q") ArrayList<String> list) {
return Response.ok(stringify(list)).build();
}
}
または MultiValuedParamConverter は再書き込みして LinkList を返すことができます。また、TestResource.conversion() のパラメーターリストは、List または LinkedList のいずれかになります。
最後に、この拡張はアレイにも機能することに注意してください。以下に例を示します。
public static class Foo {
private String foo;
public Foo(String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
}
public static class FooArrayParamConverter implements ParamConverter < Foo[] > {
@Override
public Foo[] fromString(String value) {
String[] ss = value.split(",");
Foo[] fs = new Foo[ss.length];
int i = 0;
for (String s: ss) {
fs[i++] = new Foo(s);
}
return fs;
}
@Override
public String toString(Foo[] values) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < values.length; i++) {
sb.append(values[i].getFoo()).append(",");
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}
@Provider
public static class FooArrayParamConverterProvider implements ParamConverterProvider {
@SuppressWarnings("unchecked")
@Override
public < T > ParamConverter < T > getConverter(Class < T > rawType, Type genericType, Annotation[] annotations) {
if (rawType.equals(Foo[].class));
return (ParamConverter < T > ) new FooArrayParamConverter();
}
}
@Path("")
public static class ParamConverterResource {
@GET
@Path("test")
public Response test(@QueryParam("foos") Foo[] foos) {
return Response.ok(new FooArrayParamConverter().toString(foos)).build();
}
}
java.util.Optional パラメータータイプ
RESTEasy は、複数の追加の java.util.Optional パラメータータイプを提供します。これらのパラメータータイプは、ラッパーオブジェクトタイプとして機能します。これにより、ユーザーは任意のタイプパラメーターを入力でき、Optional.orElse() などのメソッドを使用してすべての null チェックを削除できます。
@Path("/double")
@GET
public String optDouble(@QueryParam("value") OptionalDouble value) {
return Double.toString(value.orElse(4242.0));
}
上記の例は、OptionalDouble をパラメータータイプとして使用できることを示しています。値が @QueryParam で指定されていない場合は、デフォルト値が返されます。以下のパラメータータイプでは、オプションのパラメーターがサポートされています。
-
@QueryParam -
@MatrixParam -
@FormParam -
@HeaderParam -
@CookieParam
2.7.7. シリアライズ可能なプロバイダー リンクのコピーリンクがクリップボードにコピーされました!
信用できないソースから Java オブジェクトをデシリアライズすることは危険です。そのため、org.jboss.resteasy.plugins.providers.SerializableProvider はデフォルトで無効になっています。このプロバイダーの使用は推奨されません。
2.7.8. JSON プロバイダー リンクのコピーリンクがクリップボードにコピーされました!
2.7.8.1. RESTEasy Jackson2 での JsonFilter サポート リンクのコピーリンクがクリップボードにコピーされました!
JsonFilter は、@JsonFilter でクラスにアノテーションを付けることで、動的なフィルタリングを容易にします。以下の例では、nameFilter クラスからフィルターインスタンスへのマッピングを定義し、インスタンスを JSON 形式にシリアライズする際に Bean プロパティーを除外します。
@JsonFilter(value="nameFilter")
public class Jackson2Product {
protected String name;
protected int id;
public Jackson2Product() {
}
public Jackson2Product(final int id, final String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
@JsonFilter はリソースクラスにアノテーションを付け、JSON 応答でシリアライズすべきでないプロパティーをフィルターアウトします。フィルター ID とインスタンスをマップするには、別の Jackson クラスを作成し、以下の例のようにその ID とフィルターインスタンスマップを追加する必要があります。
public class ObjectFilterModifier extends ObjectWriterModifier {
public ObjectFilterModifier() {
}
@Override
public ObjectWriter modify(EndpointConfigBase<?> endpoint,
MultivaluedMap<String, Object> httpHeaders, Object valueToWrite,
ObjectWriter w, JsonGenerator jg) throws IOException {
FilterProvider filterProvider = new SimpleFilterProvider().addFilter(
"nameFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
return w.with(filterProvider);
}
}
上記の例では、メソッド modify() は応答を記述する前に、name プロパティー以外のすべてのプロパティーをフィルタリングします。これを機能させるには、RESTEasy はこのマッピング情報を知っておく必要があります。以下の例が示すように、WriterInterceptor またはサーブレットフィルターのいずれかに設定できます。
例: WriterInterceptor を使用した ObjectFilterModifier の設定
@Provider
public class JsonFilterWriteInterceptor implements WriterInterceptor{
private ObjectFilterModifier modifier = new ObjectFilterModifier();
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
//set a threadlocal modifier
ObjectWriterInjector.set(modifier);
context.proceed();
}
}
例: サーブレットフィルターを使用した ObjectFilterModifier の設定
public class ObjectWriterModifierFilter implements Filter {
private static ObjectFilterModifier modifier = new ObjectFilterModifier();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
ObjectWriterInjector.set(modifier);
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
これで、RESTEasy は ObjectFilterModifier を ThreadLocal 変数から取得して、応答の作成前に ObjectWriter を変更するように設定できます。
2.7.8.2. 時間および期間オブジェクトの JSON シリアル化 リンクのコピーリンクがクリップボードにコピーされました!
Jackson2 プロバイダーを設定せずに RESTEasy を使用して、LocalDateTime、LocalDate、または Duration クラスなどの時間および期間オブジェクトをシリアル化すると、エラーが発生します。
RESTEasy は、Jackson2 プロバイダーを使用した時間オブジェクトと期間オブジェクトのシリアル化をサポートしています。次の例は、シリアライゼーションをアクティブ化するように Jackson2 プロバイダーを設定する方法を示しています。
例: シリアライゼーション用に Jackson2 プロバイダーを設定する
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonDatatypeJacksonProducer implements ContextResolver<ObjectMapper> {
private final ObjectMapper json;
public JacksonDatatypeJacksonProducer() throws Exception {
this.json = JsonMapper.builder()
.findAndAddModules()
.build();
}
@Override
public ObjectMapper getContext(Class<?> objectType) {
return json;
}
}
2.7.8.3. JSON Binding リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy は Jakarta JSON Binding と Jakarta JSON Processing の両方をサポートします。仕様に従い、Jakarta JSON Binding のエンティティープロバイダーは、JsonValue とそのサブタイプ以外のすべてのタイプのエンティティーで Jakarta JSON Processing のエンティティープロバイダーよりも優先されます。
resteasy-json-binding-provider モジュールからの JsonBindingProvider は、JSON-B のサポートを提供します。Jakarta RESTful Web Services 2.1 の要件を満たすため、JsonBindingProvider プロバイダーは特に Jackson ペイロードで JSON ペイロードを処理する他のプロバイダーよりも優先されます。
同じ入力では、Jackson および Jakarta JSON Binding リファレンス実装からの JSON 出力は異なる場合があります。後方互換性を維持するには、resteasy.preferJacksonOverJsonB コンテキストプロパティーを true に設定し、現在のデプロイメントの JsonBindingProvider 設定を無効にします。
JBoss EAP は、同じ名前のシステムプロパティーを設定して、resteasy.preferJacksonOverJsonB コンテキストプロパティーのデフォルト値を指定することをサポートします。コンテキストおよびシステムプロパティーに値が設定されていない場合、Jackson アノテーションの Jakarta RESTful Web Services デプロイメントをスキャンし、これらのアノテーションのいずれかが見つからない場合にプロパティーを true に設定します。
2.7.9. Jakarta XML Binding プロバイダー リンクのコピーリンクがクリップボードにコピーされました!
2.7.9.1. Jakarta XML Binding および XML プロバイダー リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy は XML で Jakarta XML Binding プロバイダーをサポートします。
@XmlHeader および @Stylesheet
RESTEasy は、@org.jboss.resteasy.annotations.providers.jaxb.XmlHeader アノテーションを使用した XML ヘッダーの設定を提供します。
例: @XmlHeader アノテーションの使用
@XmlRootElement
public static class Thing {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Path("/test")
public static class TestService {
@GET
@Path("/header")
@Produces("application/xml")
@XmlHeader("<?xml-stylesheet type='text/xsl' href='${baseuri}foo.xsl' ?>")
public Thing get() {
Thing thing = new Thing();
thing.setName("bill");
return thing;
}
}
@XmlHeader は、XML 出力に XML スタイルシートヘッダーがあることを確認します。
RESTEasy にはスタイルシートヘッダーの便利なアノテーションがあります。
例: @Stylesheet アノテーションの使用
@XmlRootElement
public static class Thing {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Path("/test")
public static class TestService {
@GET
@Path("/stylesheet")
@Produces("application/xml")
@Stylesheet(type="text/css", href="${basepath}foo.xsl")
@Junk
public Thing getStyle() {
Thing thing = new Thing();
thing.setName("bill");
return thing;
}
}
2.7.9.2. Jakarta XML Binding および JSON プロバイダー リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy では、JSON プロバイダーを使用して Jakarta XML Binding アノテーションが付けられた POJO と JSON との間でマーシャリングを行うことができます。このプロバイダーは、このタスクを実行するために Jackson JSON ライブラリーをラップします。Jakarta XML Binding と同様の Java Bean ベースのモデルおよび API があります。
Jackson にすでに Jakarta RESTful Web Services 統合が含まれていますが、RESTEasy によって拡張されました。これをプロジェクトに組み込むには、Maven 依存関係を更新する必要があります。
Jackson の Maven 依存関係
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>${version.org.jboss.resteasy}</version>
<scope>provided</scope>
</dependency>
RESTEasy のデフォルトの JSON プロバイダーは Jackson2 です。JBoss EAP の以前のバージョンには Jackson1 JSON プロバイダーが含まれていました。Jackson1 プロバイダーから既存アプリケーションを移行する方法の詳細は、JBoss EAP Migration Guide を参照してください。Jackson1 プロバイダーを使用する場合は、Maven 依存関係を明示的に更新して取得 する必要があります。
以前のバージョンの JBoss EAP の RESTEasy のデフォルト JSON プロバイダーは Jettison でしたが、JBoss EAP 7 では非推奨になっています。詳細は、JBoss EAPMigration Guide を参照してください。
JSON プロバイダーの例
@XmlRootElement
public static class Thing {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Path("/test")
public static class TestService {
@GET
@Path("/thing")
@Produces("application/json")
public Thing get() {
Thing thing = new Thing();
thing.setName("the thing");
return thing;
}
}
2.7.9.2.1. Java 8 の Jackson モジュールサポート リンクのコピーリンクがクリップボードにコピーされました!
ここでは、Maven の依存関係を説明します。また、コアの Jackson モジュールが Java 8 ランタイム環境を必要としない場合に Java 8 機能をサポートするために必要な Jackson モジュールを登録する方法について説明します。これらの Jackson モジュールには以下が含まれます。
- Java 8 データ型
- Java 8 日付/時刻
以下の Maven 依存関係を追加します。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
以下の例のように、findAndRegisterModules() または ObjectMapper.registerModule() を使用してすべてのモジュールを検索し、登録することができます。
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
ObjectMapper mapper = new ObjectMapper()
.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule());
例: 期間のデータタイプ
@GET
@Path("/duration")
@Produces(MediaType.APPLICATION_JSON)
public Duration getDuration() {
return Duration.ofSeconds(5, 6);
}
例: 任意のデータタイプ
@GET
@Path("/optional/{nullParam}")
@Produces(MediaType.APPLICATION_JSON)
public Optional<String> getOptional(@PathParam("nullParam") boolean nullParameter) {
return nullParameter ? Optional.<String>empty() : Optional.of("info@example.com");
}
RESTEasy でこれらの Jackson モジュールを使用するには、ContextResolver のカスタム実装を使用する必要があります。
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonDatatypeJacksonProducer implements ContextResolver<ObjectMapper> {
private final ObjectMapper json;
public JacksonDatatypeJacksonProducer() throws Exception {
this.json = new ObjectMapper()
.findAndRegisterModules()
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Override
public ObjectMapper getContext(Class<?> objectType) {
return json;
}
}
2.7.9.2.2. デフォルトの Jackson プロバイダーの切り替え リンクのコピーリンクがクリップボードにコピーされました!
JBoss EAP 7 には Jackson 2.6.x 以上が含まれ、resteasy-jackson2-provider がデフォルトの Jackson プロバイダーになりました。
以前のリリースの JBoss EAP に含まれていたデフォルトの resteasy-jackson-provider に切り替えるには、新しいプロバイダーを除外し、jboss-deployment-structure.xml アプリケーションデプロイメント記述子ファイルに以前のプロバイダーの依存関係を追加します。
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
</exclusions>
<dependencies>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
2.7.10. Jakarta XML Binding デコレーターの作成 リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy の Jakarta XML Binding プロバイダーには、Marshaller インスタンスと Unmarshaller インスタンスを修飾するプラグ可能な方法があります。メソッドを切り離すために使用できる Marshaller または Un markler インスタンスのいずれかをトリガーできるアノテーションを作成できます。
RESTEasy での Jakarta XML Binding デコレーターの作成
Processor クラスを作成します。
-
DecoratorProcessor<Target, Annotation>を実装するクラスを作成します。ターゲットは Jakarta XML Binding Marshaller または Unmarshaller クラスです。アノテーションは、ステップ 2 で作成されます。 -
クラスに
@DecorateTypesアノテーションを付け、デコレーターがデコレートする必要のある MIME タイプを宣言します。 decorate 関数内にプロパティーまたは値を設定します。
例: Processor クラス
import org.jboss.resteasy.core.interception.DecoratorProcessor; import org.jboss.resteasy.annotations.DecorateTypes; import javax.xml.bind.Marshaller; import javax.xml.bind.PropertyException; import javax.ws.rs.core.MediaType; import javax.ws.rs.Produces; import java.lang.annotation.Annotation; @DecorateTypes({"text/*+xml", "application/*+xml"}) public class PrettyProcessor implements DecoratorProcessor<Marshaller, Pretty> { public Marshaller decorate(Marshaller target, Pretty annotation, Class type, Annotation[] annotations, MediaType mediaType) { target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); } }
-
アノテーションを作成します。
-
@Decoratorアノテーションが付けられたカスタムインターフェイスを作成します。 @Decoratorアノテーションのプロセッサーおよびターゲットを宣言します。プロセッサーは、ステップ 1 で作成されます。ターゲットは Jakarta XML BindingMarshallerまたはUnmarshallerクラスです。例:
@Decoratorアノテーションのあるカスタムインターフェイスimport org.jboss.resteasy.annotations.Decorator; @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Decorator(processor = PrettyProcessor.class, target = Marshaller.class) public @interface Pretty {}
-
- 手順 2 で作成したアノテーションを関数に追加して、入力または出力のいずれかがマーシャリングされるときにデコレートされるようにします。
Jakarta RESTful Web Services Web サービス内で適用可能な Jakarta XML Binding デコレーターが作成されました。
2.7.11. Jakarta RESTful Web Services のマルチパートプロバイダー リンクのコピーリンクがクリップボードにコピーされました!
multipart MIME 形式は、単一のメッセージに埋め込まれたコンテンツボディーのリストを渡すために使用されます。multipart MIME 形式の一例として、multipart/form-data MIME タイプが挙げられます。これは Web アプリケーションの HTML 形式のドキュメントにあり、通常はファイルをアップロードするために使用されます。この MIME タイプの form-data 形式は、インラインコンテンツのそれぞれに関連する名前がある以外は、他の multipart 形式と同じです。
RESTEasy は、multipart/form-data および multipart/* MIME タイプを許可します。RESTEasy は、multipart タイプの読み書きや、任意の List (任意の multipart タイプ) および Map (multipart/form-data のみ) オブジェクトのマーシャリングを行うためのカスタム API も提供します。
Seam の org.jboss.seam.web.MultipartFilter や Spring の org.springframework.web.multipart.MultipartResolver など、フィルターやインターセプターの支援により、multipart 解析を自動的に行うフレームワークが多数あります。ただし、着信 multipart 要求ストリームは 1 回のみ解析できます。multipart を使用する RESTEasy ユーザーは、RESTEasy がそれを取得する前にストリームを解析しないようにする必要があります。
2.7.11.1. multipart データでの入力 リンクのコピーリンクがクリップボードにコピーされました!
Jakarta RESTful Web Services サービスを作成する場合、RESTEasy は org.jboss.resteasy.plugins.providers.multipart.MultipartInput インターフェイスを提供し、すべてのマルチパート MIME タイプで読み取りできるようにします。
package org.jboss.resteasy.plugins.providers.multipart;
public interface MultipartInput {
List<InputPart> getParts();
String getPreamble();
// You must call close to delete any temporary files created
// Otherwise they will be deleted on garbage collection or on JVM exit
void close();
}
public interface InputPart {
MultivaluedMap<String, String> getHeaders();
String getBodyAsString();
<T> T getBody(Class<T> type, Type genericType) throws IOException;
<T> T getBody(org.jboss.resteasy.util.GenericType<T> type) throws IOException;
MediaType getMediaType();
boolean isContentTypeFromMessage();
}
MultipartInput は、multipart メッセージの各パーツにアクセスできる簡単なインターフェイスです。各パーツは InputPart インターフェイスによって表示され、各パートにはそれに関連するヘッダーのセットがあります。getBody() メソッドのいずれかを呼び出すと、この部分のマーシャルを解除できます。genericType パラメーターは null にすることができますが、type パラメーターは設定する必要があります。RESTEasy は、パーツのメディアタイプおよび渡すタイプ情報に基づいて MessageBodyReader を検出します。
2.7.11.1.1. multipart/mixed での入力 リンクのコピーリンクがクリップボードにコピーされました!
例: パーツのマーシャリング解除
@Path("/multipart")
public class MyService {
@PUT
@Consumes("multipart/mixed")
public void put(MultipartInput input) {
List<Customer> customers = new ArrayList...;
for (InputPart part : input.getParts()) {
Customer cust = part.getBody(Customer.class, null);
customers.add(cust);
}
input.close();
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
汎用型のメタデータの影響を受けるボディー部分をマーシャリング解除する必要があることも考えられます。この場合は、org.jboss.resteasy.util.GenericType クラスを使用できます。
例: 汎用型メタデータに影響を受けやすいタイプのマーシャリング解除
@Path("/multipart")
public class MyService {
@PUT
@Consumes("multipart/mixed")
public void put(MultipartInput input) {
for (InputPart part : input.getParts()) {
List<Customer> cust = part.getBody(new GenericType<List<Customer>>() {});
}
input.close();
}
}
GenericType の使用は、ランタイム時に汎用型情報を取得する唯一の方法であるため、必要になります。
2.7.11.1.2. multipart/mixed および java.util.List による入力 リンクのコピーリンクがクリップボードにコピーされました!
ボディーの部分が均一である場合は、各部分と各パーツを手動でマーシャリング解除する必要はありません。入力パラメーターとして java.util.List を指定できます。List タイプ宣言の汎用パラメーターを使用してマーシャリング解除されている型が必要です。
例: Customers の List のマーシャリング解除
@Path("/multipart")
public class MyService {
@PUT
@Consumes("multipart/mixed")
public void put(List<Customer> customers) {
...
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
2.7.11.1.3. multipart/form-data による入力 リンクのコピーリンクがクリップボードにコピーされました!
Jakarta RESTful Web Services サービスを作成する場合、RESTEasy は multipart/form-data MIME タイプで読み取りできるインターフェイスを提供します。multipart/form-data は、Web アプリケーションの HTML 形式のドキュメントにあり、通常はファイルをアップロードするために使用されます。form-data 形式は、インラインコンテンツのそれぞれに関連する名前がある以外は、他の multipart 形式と同じです。from-data 入力に使用されるインターフェイスは org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput です。
例: MultipartFormDataInput インターフェイス
public interface MultipartFormDataInput extends MultipartInput {
@Deprecated
Map<String, InputPart> getFormData();
Map<String, List<InputPart>> getFormDataMap();
<T> T getFormDataPart(String key, Class<T> rawType, Type genericType) throws IOException;
<T> T getFormDataPart(String key, GenericType<T> type) throws IOException;
}
これは、前述の MultipartInput と同じように機能します。
2.7.11.1.4. ultipart/form-data を含む java.utol.Map リンクのコピーリンクがクリップボードにコピーされました!
form-data では、ボディーの部分が均一である場合は、あらゆるパーツを手動でマーシャリング解除する必要はありません。入力パラメーターとして java.util.Map を指定できます。List タイプ宣言の汎用パラメーターを使用してマーシャリング解除されている型が必要です。
例: Customer オブジェクトの Map のマーシャリング解除
@Path("/multipart")
public class MyService {
@PUT
@Consumes("multipart/form-data")
public void put(Map<String, Customer> customers) {
...
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
2.7.11.2. multipart データでの出力 リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy は、multipart データを出力するための簡単な API を提供します。
package org.jboss.resteasy.plugins.providers.multipart;
public class MultipartOutput {
public OutputPart addPart(Object entity, MediaType mediaType)
public OutputPart addPart(Object entity, GenericType type, MediaType mediaType)
public OutputPart addPart(Object entity, Class type, Type genericType, MediaType mediaType)
public List<OutputPart> getParts()
public String getBoundary()
public void setBoundary(String boundary)
}
public class OutputPart {
public MultivaluedMap<String, Object> getHeaders()
public Object getEntity()
public Class getType()
public Type getGenericType()
public MediaType getMediaType()
}
multipart データを出力するには、MultipartOutput オブジェクトを作成し、addPart() メソッドを呼び出します。RESTEasy は、エンティティーオブジェクトをマーシャリングするための MessageBodyWriter を自動的に検出します。MultipartInput と同様に、汎用型メタデータに影響しやすいマーシャリングがある場合があります。この場合は、GenericType を使用します。通常は、オブジェクトとその MediaType を渡すだけで十分です。
例: multipart/mixed 形式の戻り値
@Path("/multipart")
public class MyService {
@GET
@Produces("multipart/mixed")
public MultipartOutput get() {
MultipartOutput output = new MultipartOutput();
output.addPart(new Customer("bill"), MediaType.APPLICATION_XML_TYPE);
output.addPart(new Customer("monica"), MediaType.APPLICATION_XML_TYPE);
return output;
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
2.7.11.2.1. java.util.List でのマルチ出力 リンクのコピーリンクがクリップボードにコピーされました!
ボディーの部分が均一である場合は、各パーツおよび各パーツを手動でマーシャリングしたり、MultipartOutput オブジェクトを使用したりする必要はありません。java.util.List を指定できます。これは、List 型宣言の汎用パラメーターでマーシャリングされる汎用型である必要があります。また、各パーツのメディアタイプを指定するには @PartType アノテーションを使用してメソッドにアノテーションを付ける必要もあります。
例: Customer オブジェクトの List 戻り値
@Path("/multipart")
public class MyService {
@GET
@Produces("multipart/mixed")
@PartType("application/xml")
public List<Customer> get(){
...
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
2.7.11.2.2. multipart/form-data による出力 リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy は、multipart/form-data を出力する簡単な API を提供します。
package org.jboss.resteasy.plugins.providers.multipart;
public class MultipartFormDataOutput extends MultipartOutput {
public OutputPart addFormData(String key, Object entity, MediaType mediaType)
public OutputPart addFormData(String key, Object entity, GenericType type, MediaType mediaType)
public OutputPart addFormData(String key, Object entity, Class type, Type genericType, MediaType mediaType)
public Map<String, OutputPart> getFormData()
}
multipart/form-data を出力するには、MultipartFormDataOutput オブジェクトを作成し、addFormData() メソッドを呼び出します。RESTEasy は、エンティティーオブジェクトをマーシャリングするための MessageBodyWriter を自動的に検出します。MultipartInput と同様に、汎用型メタデータに影響しやすいマーシャリングがある場合があります。この場合は、GenericType を使用します。通常は、オブジェクトとその MediaType を渡すだけで十分です。
例: multipart/form-data 形式の戻り値
@Path("/form")
public class MyService {
@GET
@Produces("multipart/form-data")
public MultipartFormDataOutput get() {
MultipartFormDataOutput output = new MultipartFormDataOutput();
output.addPart("bill", new Customer("bill"), MediaType.APPLICATION_XML_TYPE);
output.addPart("monica", new Customer("monica"), MediaType.APPLICATION_XML_TYPE);
return output;
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
2.7.11.2.3. java.util.Map による Multipart FormData Output リンクのコピーリンクがクリップボードにコピーされました!
ボディーの部分が均一である場合は、各パーツを手動でマーシャリングしたり、MultipartFormDataOutput オブジェクトを使用したりする必要はありません。java.util.Map のみを指定できます。この Map には、Map タイプ宣言の汎用パラメーターを使用してマーシャリングする汎用型が必要です。また、各パーツのメディアタイプを指定するには @PartType アノテーションを使用してメソッドにアノテーションを付ける必要もあります。
例: Customer オブジェクトの Map 戻り値
@Path("/multipart")
public class MyService {
@GET
@Produces("multipart/form-data")
@PartType("application/xml")
public Map<String, Customer> get() {
...
}
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
2.7.11.3. Multipart フォームの POJO へのマッピング リンクのコピーリンクがクリップボードにコピーされました!
multipart/form-data パッケージについて正確な知識がある場合は、POJO クラスとマップすることができます。これは、org.jboss.resteasy.annotations.providers.multipart.MultipartForm アノテーション (@MultipartForm) および Jakarta RESTful Web Services @FormParam アノテーションを使用して実現できます。これを行うには、少なくともデフォルトのコンストラクターを使用して POJO を定義し、@FormParams でフィールドとプロパティーにアノテーションを付ける必要があります。これらの @FormParams にも org.jboss.resteasy.annotations.providers.multipart.PartType (@PartType) のアノテーションを付ける必要があります (出力を作成する場合)。
例: multipart フォームの POJO へのマッピング
public class CustomerProblemForm {
@FormParam("customer")
@PartType("application/xml")
private Customer customer;
@FormParam("problem")
@PartType("text/plain")
private String problem;
public Customer getCustomer() { return customer; }
public void setCustomer(Customer cust) { this.customer = cust; }
public String getProblem() { return problem; }
public void setProblem(String problem) { this.problem = problem; }
}
POJOI クラスを定義したら、それを使用して multipart/form-data を表すことができます。
例: CustomerProblemForm の送信
@Path("portal")
public interface CustomerPortal {
@Path("issues/{id}")
@Consumes("multipart/form-data")
@PUT
public void putProblem(@MultipartForm CustomerProblemForm,
@PathParam("id") int id);
}
// Somewhere using it:
{
CustomerPortal portal = ProxyFactory.create(CustomerPortal.class, "http://example.com");
CustomerProblemForm form = new CustomerProblemForm();
form.setCustomer(...);
form.setProblem(...);
portal.putProblem(form, 333);
}
@MultipartForm アノテーションは、オブジェクトに @FormParam があり、そこからマーシャリングが必要であることを RESTEasy に指示します。また、同じオブジェクトを使用して multipart データを受信することもできます。
例: CustomerProblemForm の受信
@Path("portal")
public class CustomerPortalServer {
@Path("issues/{id})
@Consumes("multipart/form-data")
@PUT
public void putIssue(@MultipartForm CustomerProblemForm,
@PathParam("id") int id) {
... write to database...
}
}
2.7.11.4. XML-binary Optimized Packaging (XOP) リンクのコピーリンクがクリップボードにコピーされました!
一部のバイナリーコンテンツも保持する Jakarta XML Binding アノテーションが付けられた POJO がある場合は、バイナリーを base64 や 16 進などでエンコードする必要がないように送信することを選択できます。これは XOP を使用して実現でき、便利な POJO を使用しながらトランスポートが高速になります。
RESTEasy は、multipart/related としてパッケージ化された XOP メッセージを許可します。
XOP を設定するには、まず Jakarta XML Binding アノテーションが付けられた POJO が必要です。
例: Jakarta XML Binding POJO
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Xop {
private Customer bill;
private Customer monica;
@XmlMimeType(MediaType.APPLICATION_OCTET_STREAM)
private byte[] myBinary;
@XmlMimeType(MediaType.APPLICATION_OCTET_STREAM)
private DataHandler myDataHandler;
// methods, other fields ...
}
@XmlMimeType は、Jakarta XML Binding にバイナリーコンテンツの mime タイプを伝えます。これは XOP パッケージ化を行う必要はありませんが、正確なタイプが分かっている場合は設定することが推奨されます。
上記の myBinary および myDataHandler はバイナリー添付として処理され、XOP オブジェクト全体が XML として送信されます。バイナリーの代わり、それらの参照のみが生成されます。javax.activation.DataHandler は、最も一般的なサポートされているタイプです。java.io.InputStream または javax.activation.DataSource が必要な場合は、DataHandler を使用する必要があります。java.awt.Image および javax.xml.transform.SourceSome も利用できます。
例: XOP でバイナリーコンテンツを送信するクライアント
// our client interface:
@Path("mime")
public static interface MultipartClient {
@Path("xop")
@PUT
@Consumes(MultipartConstants.MULTIPART_RELATED)
public void putXop(@XopWithMultipartRelated Xop bean);
}
// Somewhere using it:
{
MultipartClient client = ProxyFactory.create(MultipartClient.class,
"http://www.example.org");
Xop xop = new Xop(new Customer("bill"), new Customer("monica"),
"Hello Xop World!".getBytes("UTF-8"),
new DataHandler(new ByteArrayDataSource("Hello Xop World!".getBytes("UTF-8"),
MediaType.APPLICATION_OCTET_STREAM)));
client.putXop(xop);
}
上記の例では、Customer クラスに Jakarta XML Binding のアノテーションが付けられていることを前提としています。
@Consumes(MultipartConstants.MULTIPART_RELATED) は、multipart/related パッケージを送信するように RESTEasy に指示するために使用されます。@XopWithMultipartRelated は、XOP メッセージ を作成するように RESTEasy に指示するために使用されます。
例: XOP を受信する RESTEasy サーバー
@Path("/mime")
public class XopService {
@PUT
@Path("xop")
@Consumes(MultipartConstants.MULTIPART_RELATED)
public void putXopWithMultipartRelated(@XopWithMultipartRelated Xop xop) {
// do very important things here
}
}
@Consumes(MultipartConstants.MULTIPART_RELATED) は、multipart/related パッケージを読み取るように RESTEasy に指示するために使用されます。@XopWithMultipartRelated は、XOP メッセージを読み取ることを RESTEasy に伝えるために使用されます。RESTEasy サーバーは、@Produces アノテーションを追加し、適切な型を返すことで、同様の方法で XOP 値を生成するように設定できます。
2.7.11.5. multipart メッセージのデフォルトのフォールバックコンテンツタイプの上書き リンクのコピーリンクがクリップボードにコピーされました!
デフォルトでは、Content-Type ヘッダーが一部にない場合、text/plain; charset=us-ascii がフォールバックとして使用されます。これは MIME RFC によって定義されます。ただし、多くのブラウザーなどの一部の Web クライアントはファイルパーツの Content-Type ヘッダーを送信しますが、multipart/form-data のすべてのフィールドについては送信しません。これにより、サーバー側で文字エンコーディングおよびマーシャリング解除エラーが発生する可能性があります。この問題を修正するには、RESTEasy の PreProcessInterceptor インフラストラクチャーを使用できます。これを使用して、リクエストごとに、RFC に準拠していない別のフォールバック値を動的に定義することができます。
例: * / *; charset=UTF-8 をデフォルトフォールバックとして設定
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
@Provider
@ServerInterceptor
public class ContentTypeSetterPreProcessorInterceptor implements PreProcessInterceptor {
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
throws Failure, WebApplicationException {
request.setAttribute(InputPart.DEFAULT_CONTENT_TYPE_PROPERTY, "*/*; charset=UTF-8");
return null;
}
}
2.7.11.6. 複数パートメッセージのコンテンツタイプの上書き リンクのコピーリンクがクリップボードにコピーされました!
インターセプターおよび InputPart.DEFAULT_CONTENT_TYPE_PROPERTY 属性を使用すると、デフォルトの Content-Type を設定できます。org.jboss.resteasy.plugins.providers.multipart.InputPart.setMediaType() を呼び出して、任意の入力部分で Content-Type をオーバーライドすることもできます。
例: Content-Type の上書き
@POST
@Path("query")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public Response setMediaType(MultipartInput input) throws IOException {
List<InputPart> parts = input.getParts();
InputPart part = parts.get(0);
part.setMediaType(MediaType.valueOf("application/foo+xml"));
String s = part.getBody(String.class, null);
...
}
2.7.11.7. multipart メッセージのデフォルトのフォールバック charset の上書き リンクのコピーリンクがクリップボードにコピーされました!
multipart メッセージの一部が、charset パラメーターのない Content-Type ヘッダーを持つ場合があります。InputPart.DEFAULT_CONTENT_TYPE_PROPERTY プロパティーが設定され、値に charset パラメーターがある場合、その値は charset パラメーターのない既存の Content-Type ヘッダーに追加されます。
また、デフォルトの charset は、定数 InputPart.DEFAULT_CHARSET_PROPERTY (resteasy.provider.multipart.inputpart.defaultCharset) を使用して指定することもできます。
例: デフォルトの charset の指定
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
@Provider
@ServerInterceptor
public class ContentTypeSetterPreProcessorInterceptor implements PreProcessInterceptor {
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
throws Failure, WebApplicationException {
request.setAttribute(InputPart.DEFAULT_CHARSET_PROPERTY, "UTF-8");
return null;
}
}
InputPart.DEFAULT_CONTENT_TYPE_PROPERTY と InputPart.DEFAULT_CHARSET_PROPERTY の両方が設定されている場合は、InputLookup .DEFAULT_CHARSET_PROPERTY の値は InputPart.DEFAULT_CONTENT_TYPE_PROPERTY の値の charset を上書きします。
2.7.11.8. RESTEasy クライアントでの multipart エンティティーの送信 リンクのコピーリンクがクリップボードにコピーされました!
multipart プロバイダーを設定する他に、multipart データを送信するように RESTEasy クライアントを設定することもできます。
RESTEasy クライアントクラスの使用
アプリケーションで RESTEasy クライアントクラスを使用するには、Maven 依存関係をプロジェクトの POM ファイルに追加する必要があります。
例: Maven 依存関係
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${version.org.jboss.resteasy}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>${version.org.jboss.resteasy}</version>
<scope>provided</scope>
</dependency>
RESTEasy クライアントを使用した multipart データの送信
マルチパートデータを送信するには、まず RESTEasy Client を設定し、マルチパートデータが含まれるように org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput オブジェクトを構築する必要があります。次に、クライアントを使用してその MultipartFormDataOutput オブジェクトを javax.ws.rs.core.GenericEntity として送信することができます。
例: RESTEasy クライアント
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://foo.com/resource");
MultipartFormDataOutput formOutputData = new MultipartFormDataOutput();
formOutputData.addFormData("part1", "this is part 1", MediaType.TEXT_PLAIN);
formOutputData.addFormData("part2", "this is part 2", MediaType.TEXT_PLAIN);
GenericEntity<MultipartFormDataOutput> data = new GenericEntity<MultipartFormDataOutput>(formOutputData) { };
Response response = target.request().put(Entity.entity(data, MediaType.MULTIPART_FORM_DATA_TYPE));
response.close();
2.7.12. RESTEasy Atom サポート リンクのコピーリンクがクリップボードにコピーされました!
RESTEasy Atom API およびプロバイダーは、RESTEasy が Atom を表すように定義する簡単なオブジェクトモデルです。API の主なクラスは org.jboss.resteasy.plugins.providers.atom パッケージにあります。RESTEasy は Jakarta XML Binding を使用して API をマーシャリングおよびアンマーシャリングします。プロバイダーは Jakarta XML Binding をベースとしており、XML を使用した Atom オブジェクトの送信のみに限定されません。RESTEasy のすべての Jakarta XML Binding プロバイダーは、JSON を含む Atom API およびプロバイダーが再利用できます。
import org.jboss.resteasy.plugins.providers.atom.Content;
import org.jboss.resteasy.plugins.providers.atom.Entry;
import org.jboss.resteasy.plugins.providers.atom.Feed;
import org.jboss.resteasy.plugins.providers.atom.Link;
import org.jboss.resteasy.plugins.providers.atom.Person;
@Path("atom")
public class MyAtomService {
@GET
@Path("feed")
@Produces("application/atom+xml")
public Feed getFeed() throws URISyntaxException {
Feed feed = new Feed();
feed.setId(new URI("http://example.com/42"));
feed.setTitle("My Feed");
feed.setUpdated(new Date());
Link link = new Link();
link.setHref(new URI("http://localhost"));
link.setRel("edit");
feed.getLinks().add(link);
feed.getAuthors().add(new Person("John Brown"));
Entry entry = new Entry();
entry.setTitle("Hello World");
Content content = new Content();
content.setType(MediaType.TEXT_HTML_TYPE);
content.setText("Nothing much");
entry.setContent(content);
feed.getEntries().add(entry);
return feed;
}
}
2.7.12.1. Atom プロバイダーでの Jakarta XML バインディングの使用 リンクのコピーリンクがクリップボードにコピーされました!
org.jboss.resteasy.plugins.providers.atom.Content クラスを使用すると、コンテンツの本文である Jakarta XML Binding アノテーションが付けられたオブジェクトをアンマーシャリングおよびマーシャリングすることができます。
例: カスタマーのエントリー
@XmlRootElement(namespace = "http://jboss.org/Customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@XmlElement
private String name;
public Customer() {
}
public Customer(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
@Path("atom")
public static class AtomServer {
@GET
@Path("entry")
@Produces("application/atom+xml")
public Entry getEntry() {
Entry entry = new Entry();
entry.setTitle("Hello World");
Content content = new Content();
content.setJAXBObject(new Customer("bill"));
entry.setContent(content);
return entry;
}
}
Content.setJAXBObject() メソッドを使用すると、Jakarta XML Binding に送信するコンテンツオブジェクトを指定して適切にマーシャルできます。XML 以外の別のベース形式を使用している場合 (application/atom+json)、アタッチされた Jakarta XML Binding オブジェクトは同じ形式でマーシャリングされます。Atom ドキュメントを入力とする場合は、Content.getJAXBObject(Class clazz) メソッドを使用して Content から Jakarta XML Binding オブジェクトを抽出することもできます。
例: カスタマーオブジェクトを抽出する Atom ドキュメント
@Path("atom")
public static class AtomServer {
@PUT
@Path("entry")
@Produces("application/atom+xml")
public void putCustomer(Entry entry) {
Content content = entry.getContent();
Customer cust = content.getJAXBObject(Customer.class);
}
}
2.7.13. YAML プロバイダー リンクのコピーリンクがクリップボードにコピーされました!
resteasy-yaml-provider モジュールはサポートされません。RESTEasy のマーシャリング解除に使用される SnakeYAML ライブラリーでセキュリティー上の問題があるため、この使用は推奨されません。
RESTEasy には、SnakeYAML ライブラリーを使用した YAML のサポートが同梱されています。
JBoss EAP 7.1 より前のリリースでは、YAML プロバイダー設定はデフォルトで有効にされていました。そのため、YAML がアプリケーションでこれを使用するよう Maven 依存関係を設定することのみが必要でした。JBoss EAP 7.1 より、YAML プロバイダーはデフォルトで無効になり、アプリケーションで明示的に有効にする必要があります。
YAML プロバイダーの有効化
アプリケーションで YAML プロバイダーを有効にするには、以下の手順を実行します。
-
javax.ws.rs.ext.Providersという名前のファイルを作成または更新します。 以下の内容をファイルに追加します。
org.jboss.resteasy.plugins.providers.YamlProvider-
WAR または JAR ファイルの
META-INF/services/フォルダーにファイルを配置します。
YAML プロバイダー Maven の依存関係
アプリケーションで YAML プロバイダーを使用するには、アプリケーションのプロジェクト POM ファイルに snakeyaml JAR 依存関係を追加する必要があります。
例: YAML の Maven 依存関係
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-yaml-provider</artifactId>
<version>${version.org.jboss.resteasy}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${version.org.yaml.snakeyaml}</version>
</dependency>
YAML プロバイダーコードの例
YAML プロバイダーは以下の mime タイプを認識します。
- text/x-yaml
- text/yaml
- application/x-yaml
以下は、リソースメソッドで YAML を使用する方法の例になります。
例: リソース生成 YAML
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/yaml")
public class YamlResource {
@GET
@Produces("text/x-yaml")
public MyObject getMyObject() {
return createMyObject();
}
...
}