<chapter id="Content_Marshalling_Providers">
   <title>Content Marshalling/Providers</title>
   <sect1 id="Default_Providers_and_default_Content_Marshalling">
      <title>Default Providers and default &REST-API; Content Marshalling</title>

      <para>

         RESTEasy can automatically marshal and unmarshal a few different message bodies.
      </para>
      <para>

         <table frame="topbot">
            <tgroup cols="2" rowsep="1" colsep="1">
               <thead>
                  <row>
                     <entry>
                        Media Types
                     </entry>
                     <entry>
                        Java Type
                     </entry>
                  </row>
               </thead>
               <tbody>
                  <row>
                     <entry>
                        application/*+xml, text/*+xml, application/*+json, application/*+fastinfoset, application/atom+*
                     </entry>
                     <entry>
                        &XML-BIND-API; annotated classes
                     </entry>
                  </row>
                  <row>
                     <entry>
                        application/*+xml, text/*+xml
                     </entry>
                     <entry>
                        org.w3c.dom.Document
                     </entry>
                  </row>
                  <row>
                     <entry>
                        */*
                     </entry>
                     <entry>
                        java.lang.String
                     </entry>
                  </row>
                  <row>
                     <entry>
                        */*
                     </entry>
                     <entry>
                        java.io.InputStream
                     </entry>
                  </row>
                  <row>
                     <entry>
                        text/plain
                     </entry>
                     <entry>
                        primitives, java.lang.String, or any type that has a String constructor, or static
                        valueOf(String) method for input, toString() for output
                     </entry>
                  </row>
                  <row>
                     <entry>
                        */*
                     </entry>
                     <entry>
                        jakarta.activation.DataSource
                     </entry>
                  </row>
                  <row>
                     <entry>
                        */*
                     </entry>
                     <entry>
                        java.io.File
                     </entry>
                  </row>
                  <row>
                     <entry>
                        */*
                     </entry>
                     <entry>
                        byte[]
                     </entry>
                  </row>
                  <row>
                     <entry>
                        application/x-www-form-urlencoded
                     </entry>
                     <entry>
                        jakarta.ws.rs.core.MultivaluedMap
                     </entry>
                  </row>
               </tbody>
            </tgroup>
         </table>

      </para>
      <para>
          <emphasis role="bold">Note. </emphasis> When a <classname>java.io.File</classname> is created, as in
      </para>
      
      <programlisting>
@Path("/test")
public class TempFileDeletionResource
{
   @POST
   @Path("post")
   public Response post(File file) throws Exception
   {
      return Response.ok(file.getPath()).build();
   }
}
      </programlisting>

      <para>
          a temporary file is created in the file system. On the server side, that temporary file will be deleted
          at the end of the invocation. On the client side, however, it is the responsibility of the user to 
          delete the temporary file.
      </para>
 
      <para>

      </para>
      <para>


      </para>
   </sect1>
   <sect1 id="Content_Marshalling_with__Provider_classes">
      <title>Content Marshalling with @Provider classes</title>

      <para>

         The &REST-API; specification allows you to plug in your own request/response body reader and writers. To do this,
         you annotate a class
         with @Provider and specify the @Produces types for a writer and @Consumes types for a reader. You must
         also implement
         a MessageBodyReader/Writer interface respectively. Here is an example:
      </para>

      <programlisting>
         @Provider
         @Produces("text/plain")
         @Consumes("text/plain")
         public class DefaultTextPlain implements MessageBodyReader, MessageBodyWriter {

            public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
               // StringTextStar should pick up strings
               return !String.class.equals(type) &amp;&amp; TypeConverter.isConvertable(type);
            }

            public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
               InputStream delegate = NoContent.noContentCheck(httpHeaders, entityStream);
               String value = ProviderHelper.readString(delegate, mediaType);
               return TypeConverter.getType(type, value);
            }

            public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
               // StringTextStar should pick up strings
               return !String.class.equals(type) &amp;&amp; !type.isArray();
            }

            public long getSize(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
               String charset = mediaType.getParameters().get("charset");
               if (charset != null)
                  try {
                     return o.toString().getBytes(charset).length;
                  } catch (UnsupportedEncodingException e) {
                     // Use default encoding.
                  }
               return o.toString().getBytes(StandardCharsets.UTF_8).length;
            }

            public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
               String charset = mediaType.getParameters().get("charset");
               if (charset == null) entityStream.write(o.toString().getBytes(StandardCharsets.UTF_8));
               else entityStream.write(o.toString().getBytes(charset));
            }
         }
      </programlisting>
      <para>
        Note that in order to support <link linkend="Asynchronous_IO">Async IO</link>, you need to implement the
        <code>AsyncMessageBodyWriter</code> interface, which requires you to implement this extra method:
      </para>
      <programlisting>
         @Provider
         @Produces("text/plain")
         @Consumes("text/plain")
         public class DefaultTextPlain implements MessageBodyReader, AsyncMessageBodyWriter {
            // ...
            public CompletionStage&lt;Void&gt; asyncWriteTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, AsyncOutputStream entityStream) {
               String charset = mediaType.getParameters().get("charset");
               if (charset == null)
                  return entityStream.asyncWrite(o.toString().getBytes(StandardCharsets.UTF_8));
               else
                  return entityStream.asyncWrite(o.toString().getBytes(charset));
            }
         }
      </programlisting>
      <para>


         The RESTEasy ServletContextLoader will automatically scan your WEB-INF/lib and classes directories for classes
         annotated with @Provider or you can manually configure them in web.xml. See Installation/Configuration.
      </para>
      <para>


      </para>
   </sect1>
   <sect1 id="MessageBodyWorkers">
      <title>Providers Utility Class</title>

      <para>

         jakarta.ws.rs.ext.Providers is a simple injectable interface that allows you to look up MessageBodyReaders,
          Writers, ContextResolvers, and ExceptionMappers. It is very useful, for instance, for implementing
          multipart providers. Content types that embed
         other random content types.
      </para>
      <para>

         <programlisting><![CDATA[
public interface Providers
{

   /**
    * Get a message body reader that matches a set of criteria. The set of
    * readers is first filtered by comparing the supplied value of
    * {@code mediaType} with the value of each reader's
    * {@link jakarta.ws.rs.Consumes}, ensuring the supplied value of
    * {@code type} is assignable to the generic type of the reader, and
    * eliminating those that do not match.
    * The list of matching readers is then ordered with those with the best
    * matching values of {@link jakarta.ws.rs.Consumes} (x/y > x&#47;* > *&#47;*)
    * sorted first. Finally, the
    * {@link MessageBodyReader#isReadable}
    * method is called on each reader in order using the supplied criteria and
    * the first reader that returns {@code true} is selected and returned.
    *
    * @param type        the class of object that is to be written.
    * @param mediaType   the media type of the data that will be read.
    * @param genericType the type of object to be produced. E.g. if the
    *                    message body is to be converted into a method parameter, this will be
    *                    the formal type of the method parameter as returned by
    *                    <code>Class.getGenericParameterTypes</code>.
    * @param annotations an array of the annotations on the declaration of the
    *                    artifact that will be initialized with the produced instance. E.g. if the
    *                    message body is to be converted into a method parameter, this will be
    *                    the annotations on that parameter returned by
    *                    <code>Class.getParameterAnnotations</code>.
    * @return a MessageBodyReader that matches the supplied criteria or null
    *         if none is found.
    */
   <T> MessageBodyReader<T> getMessageBodyReader(Class<T> type,
                                                 Type genericType, Annotation annotations[], MediaType mediaType);

   /**
    * Get a message body writer that matches a set of criteria. The set of
    * writers is first filtered by comparing the supplied value of
    * {@code mediaType} with the value of each writer's
    * {@link jakarta.ws.rs.Produces}, ensuring the supplied value of
    * {@code type} is assignable to the generic type of the reader, and
    * eliminating those that do not match.
    * The list of matching writers is then ordered with those with the best
    * matching values of {@link jakarta.ws.rs.Produces} (x/y > x&#47;* > *&#47;*)
    * sorted first. Finally, the
    * {@link MessageBodyWriter#isWriteable}
    * method is called on each writer in order using the supplied criteria and
    * the first writer that returns {@code true} is selected and returned.
    *
    * @param mediaType   the media type of the data that will be written.
    * @param type        the class of object that is to be written.
    * @param genericType the type of object to be written. E.g. if the
    *                    message body is to be produced from a field, this will be
    *                    the declared type of the field as returned by
    *                    <code>Field.getGenericType</code>.
    * @param annotations an array of the annotations on the declaration of the
    *                    artifact that will be written. E.g. if the
    *                    message body is to be produced from a field, this will be
    *                    the annotations on that field returned by
    *                    <code>Field.getDeclaredAnnotations</code>.
    * @return a MessageBodyReader that matches the supplied criteria or null
    *         if none is found.
    */
   <T> MessageBodyWriter<T> getMessageBodyWriter(Class<T> type,
                                                 Type genericType, Annotation annotations[], MediaType mediaType);

   /**
    * Get an exception mapping provider for a particular class of exception.
    * Returns the provider whose generic type is the nearest superclass of
    * {@code type}.
    *
    * @param type the class of exception
    * @return an {@link ExceptionMapper} for the supplied type or null if none
    *         is found.
    */
   <T extends Throwable> ExceptionMapper<T> getExceptionMapper(Class<T> type);

   /**
    * Get a context resolver for a particular type of context and media type.
    * The set of resolvers is first filtered by comparing the supplied value of
    * {@code mediaType} with the value of each resolver's
    * {@link jakarta.ws.rs.Produces}, ensuring the generic type of the context
    * resolver is assignable to the supplied value of {@code contextType}, and
    * eliminating those that do not match. If only one resolver matches the
    * criteria then it is returned. If more than one resolver matches then the
    * list of matching resolvers is ordered with those with the best
    * matching values of {@link jakarta.ws.rs.Produces} (x/y > x&#47;* > *&#47;*)
    * sorted first. A proxy is returned that delegates calls to
    * {@link ContextResolver#getContext(java.lang.Class)} to each matching context
    * resolver in order and returns the first non-null value it obtains or null
    * if all matching context resolvers return null.
    *
    * @param contextType the class of context desired
    * @param mediaType   the media type of data for which a context is required.
    * @return a matching context resolver instance or null if no matching
    *         context providers are found.
    */
   <T> ContextResolver<T> getContextResolver(Class<T> contextType,
                                             MediaType mediaType);
}]]></programlisting>
      </para>
      <para>


      </para>
      <para>

         A Providers instance is injectable into MessageBodyReader or Writers:
      </para>
      <para>

<programlisting>
@Provider
@Consumes("multipart/fixed")
public class MultipartProvider implements MessageBodyReader {

    private @Context Providers providers;

    ...

}
</programlisting>
      </para>
      <para>


      </para>
   </sect1>
   
   <sect1 id="Configuring_Document_Marshalling">
      <title>Configuring Document Marshalling</title>

      <para>
   
         XML document parsers are subject to a form of attack known as the XXE (Xml eXternal Entity) Attack
         (<ulink url="https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing">https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing</ulink>),
         in which expanding an external entity causes an unsafe file to be loaded. For example, the document
      </para>
      
<programlisting>
&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE foo
[&lt;!ENTITY xxe SYSTEM "file:///etc/passwd"&gt;]&gt;
&lt;search&gt;
    &lt;user&gt;bill&lt;/user&gt;
    &lt;file&gt;&amp;xxe;&lt;file&gt;
&lt;/search&gt;
</programlisting>
      
      <para>
      
      could cause the passwd file to be loaded.
      </para>
      
      <para>
      
         By default, RESTEasy's built-in unmarshaller for org.w3c.dom.Document documents will not expand external entities,
         replacing them by the empty string instead. It can be configured to replace external entities by values defined in the
         DTD by setting the parameter
   
      </para>
      
      <blockquote>resteasy.document.expand.entity.references</blockquote>
      
      <para> to "true". If configured in the web.xml file, it would be:</para>
      
<programlisting>
&lt;context-param&gt;
    &lt;param-name&gt;resteasy.document.expand.entity.references&lt;/param-name&gt;
    &lt;param-value&gt;true&lt;/param-value&gt;
&lt;/context-param&gt;
</programlisting>
      
      <para>See <xref linkend="microprofile_config"/> for more information about application configuration. </para>
      
      <para>
      
      Another way of dealing with the problem is by prohibiting DTDs, which RESTEasy does by default. This behavior
      can be changed by setting the parameter
      
      </para>
      
      <blockquote>resteasy.document.secure.disableDTDs</blockquote>
           
      <para>to "false".</para>
 
 	  <para>
 	  
 	  Documents are also subject to Denial of Service Attacks when buffers are overrun by large entities or too many
 	  attributes.  For example, if a DTD defined the following entities
 	  
 	  </para>
 	  
<programlisting>
&lt;!ENTITY foo 'foo'&gt;
&lt;!ENTITY foo1 '&amp;foo;&amp;foo;&amp;foo;&amp;foo;&amp;foo;&amp;foo;&amp;foo;&amp;foo;&amp;foo;&amp;foo;'&gt;
&lt;!ENTITY foo2 '&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;&amp;foo1;'&gt;
&lt;!ENTITY foo3 '&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;&amp;foo2;'&gt;
&lt;!ENTITY foo4 '&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;&amp;foo3;'&gt;
&lt;!ENTITY foo5 '&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;&amp;foo4;'&gt;
&lt;!ENTITY foo6 '&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;&amp;foo5;'&gt;
</programlisting>
 	  
   <para>
   then the expansion of &amp;foo6; 
   would result in 1,000,000 foos. By default, RESTEasy will limit the number of expansions and
   the number of attributes per entity. The exact behavior depends on the underlying parser. The limits
   can be turned off by setting the parameter
   </para>
   
   <blockquote>resteasy.document.secure.processing.feature</blockquote>
   
   <para>to "false".</para>
   </sect1>
   
   <sect1 id="Text_media_types">
      <title>Text media types and character sets</title>
   
   <para>
   The &REST-API; specification says
   </para>

<programlisting>
When writing responses, implementations SHOULD respect application-supplied character
set metadata and SHOULD use UTF-8 if a character set is not specified by the application
or if the application specifies a character set that is unsupported.
</programlisting>

   <para>
   On the other hand, the HTTP specification says
   </para>
   
<programlisting>
When no explicit charset parameter is provided by the sender, media subtypes of the
"text" type are defined to have a default charset value of "ISO-8859-1" when received
via HTTP. Data in character sets other than "ISO-8859-1" or its subsets MUST be labeled
with an appropriate charset value.
</programlisting>

   <para>
   It follows that, in the absence of a character set specified by a resource or resource method,
   RESTEasy SHOULD use UTF-8 as the character set for text media types, and, if it does, it MUST add an explicit 
   charset parameter to the Content-Type response header. RESTEasy started adding the explicit charset
   parameter in releases 3.1.2.Final and 3.0.22.Final, and that new behavior could cause some compatibility problems. To
   specify the previous behavior, in which UTF-8 was used for text media types, but the explicit charset
   was not appended, the parameter "resteasy.add.charset" may be set to "false". It defaults to "true".
   </para>
   
   <para>
   <emphasis role="bold">Note.</emphasis> By "text" media types, we mean
   </para>
   
   <itemizedlist>
      <listitem>a media type with type "text" and any subtype;</listitem>
      <listitem>a media type with type ""application" and subtype beginning with "xml".</listitem>
   </itemizedlist>
   
   <para>
   The latter set includes "application/xml-external-parsed-entity" and "application/xml-dtd".
   </para>
   </sect1>
   
</chapter>
