2.7. コンテンツマーシャリングおよびプロバイダー


2.7.1. デフォルトのプロバイダーとデフォルトの Jakarta RESTful Web サービスのコンテンツ

RESTEasy は、いくつかの異なるメッセージ本文を自動的にマーシャリングおよびマーシャリング解除できます。

Expand
表2.1 サポートされるメディアタイプと Java タイプ
メディアタイプJava タイプ

application/* +xmltext/* +xml、
application/* +jsonapplication/* +fastinfosetapplication/ atom+*

Jakarta XML Binding アノテーションが付けられたクラス

application/* +xmltext/* +xml

org.w3c.dom.Document

* / *

java.lang.String

* / *

java.io.InputStream

text/plain

プリミティブ、java.lang.String、または String コンストラクターを持つタイプ、または入力用の静的 valueOf(String) メソ背戸、出力用の toOf() メソッド。

* / *

javax.activation.DataSource

* / *

java.io.File

* / *

byte

application/x-www-form-urlencoded

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.charsetfalse に設定します。このパラメーターのデフォルト値は 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 は、MessageBodyReadersWritersContextResolversExceptionMappers を検索できるようにする単純なインジェクト可能なインターフェイスです。これは、他のランダムなコンテンツタイプを埋め込みする 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 インターフェイスの実装によって実行されます。

  1. カスタム POJO クラスを作成します。

    public class POJO {
      private String name;
    
      public String getName() {
        return name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    }
  2. カスタム 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();
      }
    }
  3. カスタム 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();
      }
    }
  4. カスタム 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 は ObjectFilterModifierThreadLocal 変数から取得して、応答の作成前に ObjectWriter を変更するように設定できます。

2.7.8.2. 時間および期間オブジェクトの JSON シリアル化

注記

Jackson2 プロバイダーを設定せずに RESTEasy を使用して、LocalDateTimeLocalDate、または 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 デコレーターの作成
  1. Processor クラスを作成します。

    1. DecoratorProcessor<Target, Annotation> を実装するクラスを作成します。ターゲットは Jakarta XML Binding Marshaller または Unmarshaller クラスです。アノテーションは、ステップ 2 で作成されます。
    2. クラスに @DecorateTypes アノテーションを付け、デコレーターがデコレートする必要のある MIME タイプを宣言します。
    3. 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);
          }
      }

  2. アノテーションを作成します。

    1. @Decorator アノテーションが付けられたカスタムインターフェイスを作成します。
    2. @Decorator アノテーションのプロセッサーおよびターゲットを宣言します。プロセッサーは、ステップ 1 で作成されます。ターゲットは Jakarta XML Binding Marshaller または 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 {}

  3. 手順 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 タイプ宣言の汎用パラメーターを使用してマーシャリング解除されている型が必要です。

例: CustomersList のマーシャリング解除

@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_PROPERTYInputPart.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 プロバイダーを有効にするには、以下の手順を実行します。

  1. javax.ws.rs.ext.Providers という名前のファイルを作成または更新します。
  2. 以下の内容をファイルに追加します。

    org.jboss.resteasy.plugins.providers.YamlProvider
  3. 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();
  }
...
}

Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

Red Hat ドキュメントについて

Legal Notice

Theme

© 2026 Red Hat
トップに戻る