|  | <?xml version="1.0"?> | 
|  | <!-- | 
|  |  | 
|  | Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved. | 
|  |  | 
|  | This program and the accompanying materials are made available under the | 
|  | terms of the Eclipse Public License v. 2.0, which is available at | 
|  | http://www.eclipse.org/legal/epl-2.0. | 
|  |  | 
|  | This Source Code may also be made available under the following Secondary | 
|  | Licenses when the conditions for such availability set forth in the | 
|  | Eclipse Public License v. 2.0 are satisfied: GNU General Public License, | 
|  | version 2 with the GNU Classpath Exception, which is available at | 
|  | https://www.gnu.org/software/classpath/license.html. | 
|  |  | 
|  | SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | 
|  |  | 
|  | --> | 
|  |  | 
|  | <!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents;]> | 
|  | <chapter xmlns="http://docbook.org/ns/docbook" | 
|  | version="5.0" | 
|  | xml:lang="en" | 
|  | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | 
|  | xmlns:xi="http://www.w3.org/2001/XInclude" | 
|  | xmlns:xlink="http://www.w3.org/1999/xlink" | 
|  | xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd | 
|  | http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd" | 
|  | xml:id="message-body-workers"> | 
|  | <title>JAX-RS Entity Providers</title> | 
|  | <section> | 
|  | <title>Introduction</title> | 
|  | <para> | 
|  | Entity payload, if present in an received HTTP message, is passed to Jersey from an I/O container as an input stream. | 
|  | The stream may, for example, contain data represented as a plain text, XML or JSON document. However, in many JAX-RS | 
|  | components that process these inbound data, such as resource methods or client responses, the JAX-RS API user can | 
|  | access the inbound entity as an arbitrary Java object that is created from the content of the input stream based on | 
|  | the representation type information. For example, an entity created from an input stream that contains data | 
|  | represented as a XML document, can be converted to a custom JAXB bean. | 
|  | Similar concept is supported for the outbound entities. An entity returned from the resource method in the form | 
|  | of an arbitrary Java object can be serialized by Jersey into a container output stream as a specified representation. | 
|  | Of course, while JAX-RS implementations do provide default support for most common combinations of Java type and it's | 
|  | respective on-the-wire representation formats, JAX-RS implementations do not support the conversion described above | 
|  | for any arbitrary Java type and any arbitrary representation format by default. Instead, a generic extension concept | 
|  | is exposed in JAX-RS API to allow application-level customizations of this JAX-RS runtime to support for entity | 
|  | conversions. The JAX-RS extension API components that provide the user-level extensibility are typically referred to | 
|  | by several terms with the same meaning, such as <emphasis>entity providers</emphasis>, | 
|  | <emphasis>message body providers</emphasis>, <emphasis>message body workers</emphasis> or | 
|  | <emphasis>message body readers and writers</emphasis>. You may find all these terms used interchangeably throughout | 
|  | the user guide and they all refer to the same concept. | 
|  | </para> | 
|  | <para> | 
|  | In JAX-RS extension API (or SPI - service provider interface, if you like) the concept is captured in 2 interfaces. | 
|  | One for handling inbound entity representation-to-Java de-serialization - &jaxrs.ext.MessageBodyReader; and the other | 
|  | one for handling the outbound entity Java-to-representation serialization - &jaxrs.ext.MessageBodyWriter;. | 
|  | A &lit.jaxrs.ext.MessageBodyReader;, as the name suggests, is an extension that supports reading the message body | 
|  | representation from an input stream and converting the data into an instance of a specific Java type. | 
|  | A &lit.jaxrs.ext.MessageBodyWriter; is then responsible for converting a message payload from an instance of a | 
|  | specific Java type into a specific representation format that is sent over the wire to the other party as part of an | 
|  | HTTP message exchange. | 
|  | Both of these providers can be used to provide message payload serialization and de-serialization support on the | 
|  | server as well as the client side. A message body reader or writer is always used whenever a HTTP request or | 
|  | response contains an entity and the entity is either requested by the application code (e.g. injected as a parameter | 
|  | of JAX-RS resource method or a response entity read on the client from a &jaxrs.core.Response;) or has to be | 
|  | serialized and sent to the other party (e.g. an instance returned from a JAX-RS resource method or a request | 
|  | entity sent by a JAX-RS client). | 
|  | </para> | 
|  | </section> | 
|  | <section> | 
|  | <title>How to Write Custom Entity Providers</title> | 
|  | <para> | 
|  | A best way how to learn about entity providers is to walk through an example of writing one. Therefore we will | 
|  | describe here the process of implementing a custom &jaxrs.ext.MessageBodyWriter; and | 
|  | &jaxrs.ext.MessageBodyReader; using a practical example. Let's first setup the stage by defining a JAX-RS | 
|  | resource class for the server side story of our application. | 
|  |  | 
|  | <example> | 
|  | <title>Example resource class</title> | 
|  | <programlisting language="java" linenumbering="numbered">@Path("resource") | 
|  | public class MyResource { | 
|  | @GET | 
|  | @Produces("application/xml") | 
|  | public MyBean getMyBean() { | 
|  | return new MyBean("Hello World!", 42); | 
|  | } | 
|  |  | 
|  | @POST | 
|  | @Consumes("application/xml") | 
|  | public String postMyBean(MyBean myBean) { | 
|  | return myBean.anyString; | 
|  | } | 
|  | }</programlisting> | 
|  | </example> | 
|  |  | 
|  | The resource class defines &lit.http.GET; and &lit.http.POST; resource methods. Both methods work with an entity | 
|  | that is an instance of <literal>MyBean</literal>. | 
|  | </para> | 
|  | <para> | 
|  | The <literal>MyBean</literal> class is defined in the next example: | 
|  |  | 
|  | <example> | 
|  | <title>MyBean entity class</title> | 
|  | <programlisting language="java" linenumbering="numbered">@XmlRootElement | 
|  | public class MyBean { | 
|  | @XmlElement | 
|  | public String anyString; | 
|  | @XmlElement | 
|  | public int anyNumber; | 
|  |  | 
|  | public MyBean(String anyString, int anyNumber) { | 
|  | this.anyString = anyString; | 
|  | this.anyNumber = anyNumber; | 
|  | } | 
|  |  | 
|  | // empty constructor needed for deserialization by JAXB | 
|  | public MyBean() { | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return "MyBean{" + | 
|  | "anyString='" + anyString + '\'' + | 
|  | ", anyNumber=" + anyNumber + | 
|  | '}'; | 
|  | } | 
|  | }</programlisting> | 
|  | </example> | 
|  | </para> | 
|  | <section> | 
|  | <title>MessageBodyWriter</title> | 
|  | <para> | 
|  | The <literal>MyBean</literal> is a JAXB-annotated POJO. In &lit.http.GET; resource method we return | 
|  | the instance of MyBean and we would like Jersey runtime to serialize it into XML and write | 
|  | it as an entity body to the response output stream. We design a custom &lit.jaxrs.ext.MessageBodyWriter; | 
|  | that can serialize this POJO into XML. See the following code sample: | 
|  |  | 
|  | <note> | 
|  | <para> | 
|  | Please note, that this is only a demonstration of how to write a custom entity provider. | 
|  | Jersey already contains default support for entity providers that can serialize JAXB beans | 
|  | into XML. | 
|  | </para> | 
|  | </note> | 
|  |  | 
|  | <example> | 
|  | <title>MessageBodyWriter example</title> | 
|  | <programlisting language="java" linenumbering="numbered"><![CDATA[@Produces("application/xml") | 
|  | public class MyBeanMessageBodyWriter implements MessageBodyWriter<MyBean> { | 
|  |  | 
|  | @Override | 
|  | public boolean isWriteable(Class<?> type, Type genericType, | 
|  | Annotation[] annotations, MediaType mediaType) { | 
|  | return type == MyBean.class; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public long getSize(MyBean myBean, Class<?> type, Type genericType, | 
|  | Annotation[] annotations, MediaType mediaType) { | 
|  | // deprecated by JAX-RS 2.0 and ignored by Jersey runtime | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void writeTo(MyBean myBean, | 
|  | Class<?> type, | 
|  | Type genericType, | 
|  | Annotation[] annotations, | 
|  | MediaType mediaType, | 
|  | MultivaluedMap<String, Object> httpHeaders, | 
|  | OutputStream entityStream) | 
|  | throws IOException, WebApplicationException { | 
|  |  | 
|  | try { | 
|  | JAXBContext jaxbContext = JAXBContext.newInstance(MyBean.class); | 
|  |  | 
|  | // serialize the entity myBean to the entity output stream | 
|  | jaxbContext.createMarshaller().marshal(myBean, entityStream); | 
|  | } catch (JAXBException jaxbException) { | 
|  | throw new ProcessingException( | 
|  | "Error serializing a MyBean to the output stream", jaxbException); | 
|  | } | 
|  | } | 
|  | }]]></programlisting> | 
|  | </example> | 
|  | </para> | 
|  | <para> | 
|  | The <literal>MyBeanMessageBodyWriter</literal> implements the &lit.jaxrs.ext.MessageBodyWriter; | 
|  | interface that contains three methods. In the next sections we'll explore these methods more closely. | 
|  | </para> | 
|  | <section> | 
|  | <title> | 
|  | <literal>MessageBodyWriter.isWriteable</literal> | 
|  | </title> | 
|  | <para> | 
|  | A method <literal>isWriteable</literal> | 
|  | should return true if the &lit.jaxrs.ext.MessageBodyWriter; is able to write the given type. Method | 
|  | does not decide only based on the Java type of the entity but also on annotations attached to the entity | 
|  | and the requested representation media type. | 
|  | </para> | 
|  | <para> | 
|  | Parameters <literal>type</literal> and <literal>genericType</literal> both define the entity, | 
|  | where <literal>type</literal> is a raw Java type | 
|  | (for example, a <literal>java.util.List</literal> class) and <literal>genericType</literal> is a | 
|  | &jdk6.ParameterizedType; including generic information (for example <literal>List<String></literal>). | 
|  | </para> | 
|  | <para> | 
|  | Parameter <literal>annotations</literal> contains annotations that are either attached to the resource | 
|  | method and/or annotations that are attached to the entity by building response like in the following piece | 
|  | of code: | 
|  |  | 
|  | <example> | 
|  | <title>Example of assignment of annotations to a response entity</title> | 
|  | <programlisting language="java" linenumbering="numbered">@Path("resource") | 
|  | public static class AnnotatedResource { | 
|  |  | 
|  | @GET | 
|  | public Response get() { | 
|  | Annotation annotation = AnnotatedResource.class | 
|  | .getAnnotation(Path.class); | 
|  | return Response.ok() | 
|  | .entity("Entity", new Annotation[] {annotation}).build(); | 
|  | } | 
|  | }</programlisting> | 
|  | </example> | 
|  |  | 
|  | In the example above, the &lit.jaxrs.ext.MessageBodyWriter; would get | 
|  | <literal>annotations</literal> parameter containing a JAX-RS <literal>@GET</literal> annotation | 
|  | as it annotates the resource method and also a <literal>@Path</literal> annotation as it | 
|  | is passed in the response (but not because it annotates the resource; only resource | 
|  | method annotations are included). In the case of <literal>MyResource</literal> | 
|  | and method <literal>getMyBean</literal> the annotations would contain the | 
|  | &jaxrs.GET; and the &jaxrs.Produces; annotation. | 
|  | </para> | 
|  | <para> | 
|  | The last parameter of the <literal>isWriteable</literal> method is the <literal>mediaType</literal> | 
|  | which is the media type attached to the response entity by annotating the resource method with a | 
|  | &lit.jaxrs.Produces; annotation or the request media type specified in the JAX-RS Client API. | 
|  | In our example, the media type passed to providers for the resource <literal>MyResource</literal> and method | 
|  | <literal>getMyBean</literal> would be <literal>"application/xml"</literal>. | 
|  | </para> | 
|  | <para> | 
|  | In our implementation of the <literal>isWriteable</literal> method, we | 
|  | just check that the type is <literal>MyBean</literal>. Please note, that | 
|  | this method might be executed multiple times by Jersey runtime as Jersey needs to check | 
|  | whether this provider can be used for a particular combination of entity Java type, media type, and attached | 
|  | annotations, which may be potentially a performance hog. You can limit the number of execution by | 
|  | properly defining the &lit.jaxrs.Produces; annotation on the &lit.jaxrs.ext.MessageBodyWriter;. | 
|  | In our case thanks to &lit.jaxrs.Produces; annotation, the provider will be considered | 
|  | as writeable (and the method <literal>isWriteable</literal> might be executed) only if the | 
|  | media type of the outbound message is <literal>"application/xml"</literal>. Additionally, the provider | 
|  | will only be considered as possible candidate and its <literal>isWriteable</literal> method will | 
|  | be executed, if the generic type of the provider is either a sub class or super class of | 
|  | <literal>type</literal> parameter. | 
|  | </para> | 
|  | </section> | 
|  | <section> | 
|  | <title> | 
|  | <literal>MessageBodyWriter.writeTo</literal> | 
|  | </title> | 
|  | <para> | 
|  | Once a message body writer is selected as the most appropriate (see the <xref linkend="providers-selection" /> | 
|  | for more details on entity provider selection), its <literal>writeTo</literal> method is invoked. This method | 
|  | receives parameters with the same meaning as in <literal>isWriteable</literal> as well as a few additional ones. | 
|  | </para> | 
|  | <para> | 
|  | In addition to the parameters already introduced, the <literal>writeTo</literal> method defies also | 
|  | <literal>httpHeaders</literal> parameter, that contains HTTP headers associated with the | 
|  | outbound message. | 
|  |  | 
|  | <note> | 
|  | <para> | 
|  | When a &lit.jaxrs.ext.MessageBodyWriter; is invoked, the headers still can be modified in this point | 
|  | and any modification will be reflected in the outbound HTTP message being sent. The modification of | 
|  | headers must however happen before a first byte is written to the supplied output stream. | 
|  | </para> | 
|  | </note> | 
|  | </para> | 
|  | <para> | 
|  | Another new parameter, <literal>myBean</literal>, contains the entity instance to be serialized (the type of | 
|  | entity corresponds to generic type of &lit.jaxrs.ext.MessageBodyWriter;). Related parameter | 
|  | <literal>entityStream</literal> contains the entity output stream to which the method should serialize the entity. | 
|  | In our case we use JAXB to marshall the entity into the <literal>entityStream</literal>. Note, that the | 
|  | <literal>entityStream</literal> is not closed at the end of method; the stream will be closed by Jersey. | 
|  | <important> | 
|  | <para> | 
|  | Do not close the entity output stream in the <literal>writeTo</literal> method of your | 
|  | &lit.jaxrs.ext.MessageBodyWriter; implementation. | 
|  | </para> | 
|  | </important> | 
|  | </para> | 
|  | </section> | 
|  |  | 
|  | <section> | 
|  | <title> | 
|  | <literal>MessageBodyWriter.getSize</literal> | 
|  | </title> | 
|  | <para> | 
|  | The method is deprecated since JAX-RS 2.0 and Jersey 2 ignores the return value. In JAX-RS 1.0 the | 
|  | method could return the size of the entity that would be then used for "Content-Length" response | 
|  | header. In Jersey 2.0 the "Content-Length" parameter is computed automatically using an internal | 
|  | outbound entity buffering. For details about configuration options of outbound entity buffering see the javadoc | 
|  | of &jersey.message.MessageProperties;, property <literal>OUTBOUND_CONTENT_LENGTH_BUFFER</literal> | 
|  | which configures the size of the buffer. | 
|  | <note> | 
|  | <para> | 
|  | You can disable the Jersey outbound entity buffering by setting the buffer size to 0. | 
|  | </para> | 
|  | </note> | 
|  | </para> | 
|  | </section> | 
|  | <section> | 
|  | <title>Testing a &lit.jaxrs.ext.MessageBodyWriter;</title> | 
|  | <para> | 
|  | Before testing the <literal>MyBeanMessageBodyWriter</literal>, the writer must | 
|  | be registered as a custom JAX-RS extension provider. It should either be added to your application | 
|  | &jersey.server.ResourceConfig;, or returned from your custom &jaxrs.core.Application; sub-class, or | 
|  | annotated with &jaxrs.ext.Provider; annotation to leverage JAX-RS provider auto-discovery feature. | 
|  | </para> | 
|  | <para> | 
|  | After registering the <literal>MyBeanMessageBodyWriter</literal> and <literal>MyResource</literal> class | 
|  | in our application, the request can be initiated (in this example from Client API). | 
|  |  | 
|  | <example xml:id="client-get-call"> | 
|  | <title>Client code testing MyBeanMessageBodyWriter</title> | 
|  | <programlisting language="java" linenumbering="numbered" >WebTarget webTarget = // initialize web target to the context root | 
|  | // of example application | 
|  | Response response = webTarget.path("resource") | 
|  | .request(MediaType.APPLICATION_XML).get(); | 
|  | System.out.println(response.getStatus()); | 
|  | String myBeanXml = response.readEntity(String.class); | 
|  | System.out.println(myBeanXml);</programlisting> | 
|  | </example> | 
|  |  | 
|  | The client code initiates the &lit.http.GET; which will be matched to the resource method | 
|  | <literal>MyResource.getMyBean()</literal>. The response entity is de-serialized as a <literal>String</literal>. | 
|  | </para> | 
|  | <para> | 
|  | The result of console output is: | 
|  |  | 
|  | <example> | 
|  | <title>Result of MyBeanMessageBodyWriter test</title> | 
|  | <screen language="text" linenumbering="unnumbered"><![CDATA[200 | 
|  | <?xml version="1.0" encoding="UTF-8" standalone="yes"?><myBean> | 
|  | <anyString>Hello World!</anyString><anyNumber>42</anyNumber></myBean>]]></screen> | 
|  | </example> | 
|  |  | 
|  | The returned status is 200 and the entity is stored in the response in a <literal>XML</literal> format. | 
|  | Next, we will look at how the Jersey de-serializes this XML document into a <literal>MyBean</literal> consumed by | 
|  | our &lit.http.POST; resource method. | 
|  | </para> | 
|  | </section> | 
|  | </section> | 
|  | <section> | 
|  | <title>MessageBodyReader</title> | 
|  | <para> | 
|  | In order to de-serialize the entity of <literal>MyBean</literal> on the server or the client, we need to implement | 
|  | a custom &jaxrs.ext.MessageBodyReader;. | 
|  | <note> | 
|  | <para> | 
|  | Please note, that this is only a demonstration of how to write a custom entity provider. | 
|  | Jersey already contains default support for entity providers that can serialize JAXB beans | 
|  | into XML. | 
|  | </para> | 
|  | </note> | 
|  | </para> | 
|  | <para> | 
|  | Our &lit.jaxrs.ext.MessageBodyReader; implementation is listed in <xref linkend="mbw.ex.mbr" />. | 
|  |  | 
|  | <example xml:id="mbw.ex.mbr"> | 
|  | <title>MessageBodyReader example</title> | 
|  | <programlisting language="java" linenumbering="numbered"><![CDATA[public static class MyBeanMessageBodyReader | 
|  | implements MessageBodyReader<MyBean> { | 
|  |  | 
|  | @Override | 
|  | public boolean isReadable(Class<?> type, Type genericType, | 
|  | Annotation[] annotations, MediaType mediaType) { | 
|  | return type == MyBean.class; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public MyBean readFrom(Class<MyBean> type, | 
|  | Type genericType, | 
|  | Annotation[] annotations, MediaType mediaType, | 
|  | MultivaluedMap<String, String> httpHeaders, | 
|  | InputStream entityStream) | 
|  | throws IOException, WebApplicationException { | 
|  |  | 
|  | try { | 
|  | JAXBContext jaxbContext = JAXBContext.newInstance(MyBean.class); | 
|  | MyBean myBean = (MyBean) jaxbContext.createUnmarshaller() | 
|  | .unmarshal(entityStream); | 
|  | return myBean; | 
|  | } catch (JAXBException jaxbException) { | 
|  | throw new ProcessingException("Error deserializing a MyBean.", | 
|  | jaxbException); | 
|  | } | 
|  | } | 
|  | }]]></programlisting> | 
|  | </example> | 
|  |  | 
|  | It is obvious that the &lit.jaxrs.ext.MessageBodyReader; interface is similar to &lit.jaxrs.ext.MessageBodyWriter;. | 
|  | In the next couple of sections we will explore it's API methods. | 
|  | </para> | 
|  | <section> | 
|  | <title><literal>MessageBodyReader.isReadable</literal></title> | 
|  | <para> | 
|  | It defines the method <literal>isReadable()</literal> which has a very similar meaning as method | 
|  | <literal>isWriteable()</literal> in &lit.jaxrs.ext.MessageBodyWriter;. The method returns &lit.true; | 
|  | if it is able to de-serialize the given type. The <literal>annotations</literal> parameter contains annotations | 
|  | that are attached to the entity parameter in the resource method. In our &lit.http.POST; resource | 
|  | method <literal>postMyBean</literal> the entity parameter <literal>myBean</literal> is not | 
|  | annotated, therefore no annotation will be passed to the isReadable. The <literal>mediaType</literal> | 
|  | parameter contains the entity media type. The media type, in our case, must be consumable by the &lit.http.POST; | 
|  | resource method, which is specified by placing a JAX-RS &jaxrs.Consumes; annotation to the method. | 
|  | The resource method <literal>postMyBean()</literal> is annotated with | 
|  | <literal>@Consumes("application/xml")</literal>, | 
|  | therefore for purpose of de-serialization of entity for the <literal>postMyBean()</literal> method, | 
|  | only requests with entities represented as <literal>"application/xml"</literal> | 
|  | media type will match the method. However, this method might be executed for entity types that are sub classes | 
|  | or super classes of the declared generic type on the &lit.jaxrs.ext.MessageBodyReader; will be also considered. | 
|  | It is a responsibility of the <literal>isReadable</literal> method to decide whether it is able | 
|  | to de-serialize the entity and type comparison is one of the basic decision steps. | 
|  | <tip> | 
|  | <para> | 
|  | In order to reduce number of <literal>isReadable</literal> executions, always define correctly the consumable | 
|  | media type(s) with the &lit.jaxrs.Consumes; annotation on your custom &lit.jaxrs.ext.MessageBodyReader;. | 
|  | </para> | 
|  | </tip> | 
|  | </para> | 
|  | </section> | 
|  | <section> | 
|  | <title><literal>MessageBodyReader.readFrom</literal></title> | 
|  | <para> | 
|  | The <literal>readForm()</literal> method gets the parameters with the same meaning as in | 
|  | <literal>isReadable()</literal>. The additional <literal>entityStream</literal> parameter provides a handle | 
|  | to the entity input stream from which the entity bytes should be read and de-serialized into a Java entity which | 
|  | is then returned from the method. Our <literal>MyBeanMessageBodyReader</literal> de-serializes the incoming | 
|  | XML data into an instance of <literal>MyBean</literal> using JAXB. | 
|  |  | 
|  | <important> | 
|  | <para> | 
|  | Do not close the entity input stream in your &lit.jaxrs.ext.MessageBodyReader; implementation. The stream | 
|  | will be automatically closed by Jersey runtime. | 
|  | </para> | 
|  | </important> | 
|  | </para> | 
|  | </section> | 
|  | <section> | 
|  | <title>Testing a &lit.jaxrs.ext.MessageBodyWriter;</title> | 
|  |  | 
|  | <para> | 
|  | Now let's send a test request using the JAX-RS Client API. | 
|  |  | 
|  | <example> | 
|  | <title>Testing MyBeanMessageBodyReader</title> | 
|  | <programlisting language="java" linenumbering="numbered"><![CDATA[final MyBean myBean = new MyBean("posted MyBean", 11); | 
|  | Response response = webTarget.path("resource").request("application/xml") | 
|  | .post(Entity.entity(myBean, "application/xml")); | 
|  |  | 
|  | System.out.println(response.getStatus()); | 
|  | final String responseEntity = response.readEntity(String.class); | 
|  | System.out.println(responseEntity); | 
|  | ]]></programlisting> | 
|  | </example> | 
|  | </para> | 
|  | <para> | 
|  | The console output is: | 
|  |  | 
|  | <example> | 
|  | <title>Result of testing MyBeanMessageBodyReader</title> | 
|  | <screen language="text" linenumbering="unnumbered"><![CDATA[200 | 
|  | posted MyBean]]></screen> | 
|  | </example> | 
|  | </para> | 
|  | </section> | 
|  | <section> | 
|  | <title>Using Entity Providers with JAX-RS Client API</title> | 
|  | <para> | 
|  | Both, &lit.jaxrs.ext.MessageBodyReader; and &lit.jaxrs.ext.MessageBodyWriter; can be registered in a | 
|  | configuration of JAX-RS Client API components typically without any need to change their code. The example | 
|  | <xref linkend="mbw.ex.client.mbr.reg" /> is a variation on the <xref linkend="client-get-call" /> | 
|  | listed in one of the previous sections. | 
|  |  | 
|  | <example xml:id="mbw.ex.client.mbr.reg"> | 
|  | <title>MessageBodyReader registered on a JAX-RS client</title> | 
|  |  | 
|  | <programlisting language="java" linenumbering="numbered"><![CDATA[Client client = ClientBuilder.newBuilder() | 
|  | .register(MyBeanMessageBodyReader.class).build(); | 
|  |  | 
|  | Response response = client.target("http://example/comm/resource") | 
|  | .request(MediaType.APPLICATION_XML).get(); | 
|  | System.out.println(response.getStatus()); | 
|  | MyBean myBean = response.readEntity(MyBean.class); | 
|  | System.out.println(myBean);]]></programlisting> | 
|  | </example> | 
|  | </para> | 
|  | <para> | 
|  | The code above registers <literal>MyBeanMessageBodyReader</literal> to the &jaxrs.client.Client; configuration | 
|  | using a &jaxrs.client.ClientBuilder; which means that the provider will be used for any &jaxrs.client.WebTarget; | 
|  | produced by the <literal>client</literal> instance. | 
|  | <note> | 
|  | <para> | 
|  | You could also register the JAX-RS entity (and any other) providers to individual | 
|  | &lit.jaxrs.client.WebTarget; instances produced by the client. | 
|  | </para> | 
|  | </note> | 
|  |  | 
|  | Then, using the fluent chain of method invocations, a resource target pointing to our | 
|  | <literal>MyResource</literal> is defined, a HTTP &lit.http.GET; request is invoked. | 
|  | The response entity is then read as an instance of a <literal>MyBean</literal> type by invoking the | 
|  | <literal>response.readEntity</literal> method, that internally locates the registered | 
|  | <literal>MyBeanMessageBodyReader</literal> and uses it for entity de-serialization. | 
|  | </para> | 
|  | <para> | 
|  | The console output for the example is: | 
|  | <example> | 
|  | <title>Result of client code execution</title> | 
|  | <screen language="text" linenumbering="unnumbered"><![CDATA[200 | 
|  | MyBean{anyString='Hello World!', anyNumber=42}]]></screen> | 
|  | </example> | 
|  | </para> | 
|  | </section> | 
|  | </section> | 
|  | </section> | 
|  |  | 
|  | <section xml:id="providers-selection"> | 
|  | <title>Entity Provider Selection</title> | 
|  |  | 
|  | <para> | 
|  | Usually there are many entity providers registered on the server or client side (be default there must be | 
|  | at least providers mandated by the JAX-RS specification, such as providers for primitive types, byte array, | 
|  | JAXB beans, etc.). | 
|  | JAX-RS defines an algorithm for selecting the most suitable provider for entity processing. This algorithm | 
|  | works with information such as entity Java type and on-the-wire media type representation of entity, and searches | 
|  | for the most suitable entity provider from the list of available providers based on the supported media type | 
|  | declared on each provider (defined by &lit.jaxrs.Produces; or &lit.jaxrs.Consumes; on the provider class) | 
|  | as well as based on the generic type declaration of the available providers. When a list of suitable candidate | 
|  | entity providers is selected and sorted based on the rules defined in JAX-RS specification, a JAX-RS runtime | 
|  | then it invokes <literal>isReadable</literal> or <literal>isWriteable</literal> method respectively on each | 
|  | provider in the list until a first provider is found that returns &lit.true;. This provider is then used to | 
|  | process the entity. | 
|  | </para> | 
|  | <para> | 
|  | The following steps describe the algorithm for selecting a &lit.jaxrs.ext.MessageBodyWriter; (extracted | 
|  | from JAX-RS with little modifications). The steps refer to the previously discussed example application. | 
|  | The &lit.jaxrs.ext.MessageBodyWriter; is searched for purpose of deserialization of <literal>MyBean</literal> | 
|  | entity returned from the method <literal>getMyBean</literal>. So, <emphasis>type is <literal>MyBean</literal> | 
|  | and media type <literal>"application/xml"</literal></emphasis>. Let's assume the runtime contains also | 
|  | registered providers, namely: | 
|  |  | 
|  | <simplelist> | 
|  | <member> | 
|  | <literal>A</literal>: <literal>@Produces("application/*")</literal> with generic type | 
|  | <literal><Object></literal> | 
|  | </member> | 
|  | <member> | 
|  | <literal>B</literal>: <literal>@Produces("*/*")</literal> with generic type <literal><MyBean></literal> | 
|  | </member> | 
|  | <member> | 
|  | <literal>C</literal>: <literal>@Produces("text/plain")</literal> with generic type | 
|  | <literal><MyBean></literal> | 
|  | </member> | 
|  | <member> | 
|  | <literal>D</literal>: <literal>@Produces("application/xml")</literal> with generic type | 
|  | <literal><Object></literal> | 
|  | </member> | 
|  | <member> | 
|  | <literal>MyBeanMessageBodyWriter</literal>: <literal>@Produces("application/xml")</literal> with generic | 
|  | type <literal><MyBean></literal> | 
|  | </member> | 
|  | </simplelist> | 
|  | </para> | 
|  | <para> | 
|  | The algorithm executed by a JAX-RS runtime to select a proper &lit.jaxrs.ext.MessageBodyWriter; implementation | 
|  | is illustrated in <xref linkend="mbw.writer.selection.algorithm" />. | 
|  | </para> | 
|  | <procedure xml:id="mbw.writer.selection.algorithm"> | 
|  | <title>&lit.jaxrs.ext.MessageBodyWriter; Selection Algorithm</title> | 
|  | <step> | 
|  | <para> | 
|  | Obtain the object that will be mapped to the message entity body. For a return type of Response | 
|  | or subclasses, the object is the value of the entity property, for other return types it is the returned | 
|  | object. | 
|  | </para> | 
|  | <para> | 
|  | So in our case, for the resource method <literal>getMyBean</literal> the type will | 
|  | be <literal>MyBean</literal>. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | Determine the media type of the response. | 
|  | </para> | 
|  | <para> | 
|  | In our case, for resource method <literal>getMyBean</literal> | 
|  | annotated with <literal>@Produces("application/xml")</literal>, the media type will be | 
|  | <literal>"application/xml"</literal>. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | Select the set of MessageBodyWriter providers that support the object and media | 
|  | type of the message entity body. | 
|  | </para> | 
|  | <para> | 
|  | In our case, for entity media type <literal>"application/xml"</literal> | 
|  | and type <literal>MyBean</literal>, the appropriate &lit.jaxrs.ext.MessageBodyWriter; will | 
|  | be the <literal>A</literal>, <literal>B</literal>, <literal>D</literal> | 
|  | and <literal>MyBeanMessageBodyWriter</literal>. The provider <literal>C</literal> does | 
|  | not define the appropriate | 
|  | media type. <literal>A</literal> and <literal>B</literal> are fine as | 
|  | their type is more generic and compatible with <literal>"application/xml"</literal>. | 
|  | </para> | 
|  | </step> | 
|  | <step xml:id="mbw.writer.selection.algorithm.sortStep"> | 
|  | <para> | 
|  | Sort the selected MessageBodyWriter providers with a primary key of generic type where providers | 
|  | whose generic type is the nearest superclass of the object class are sorted first and a secondary key of | 
|  | media type. Additionally, JAX-RS specification mandates that custom, user registered providers have to | 
|  | be sorted ahead of default providers provided by JAX-RS implementation. This is used as a tertiary | 
|  | comparison key. User providers are places prior to Jersey internal providers in to the final ordered list. | 
|  | </para> | 
|  | <para> | 
|  | The sorted providers will be: <literal>MyBeanMessageBodyWriter</literal>, | 
|  | <literal>B</literal>. <literal>D</literal>, <literal>A</literal>. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | Iterate through the sorted &lit.jaxrs.ext.MessageBodyWriter; providers and, utilizing the | 
|  | <literal>isWriteable</literal> method of each until you find a &lit.jaxrs.ext.MessageBodyWriter; that | 
|  | returns &lit.true;. | 
|  | </para> | 
|  | <para> | 
|  | The first provider in the list - our <literal>MyBeanMessageBodyWriter</literal> returns &lit.true; as | 
|  | it compares types and the types matches. If it would return &lit.false;, the next provider | 
|  | <literal>B</literal> would by check by invoking its <literal>isWriteable</literal> method. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | If step 5 locates a suitable &lit.jaxrs.ext.MessageBodyWriter; then use its writeTo method to map the | 
|  | object to the entity body. | 
|  | </para> | 
|  | <para> | 
|  | <literal>MyBeanMessageBodyWriter.writeTo</literal> will be executed and it will serialize the | 
|  | entity. | 
|  | </para> | 
|  | <stepalternatives> | 
|  | <step> | 
|  | <para> | 
|  | Otherwise, the server runtime MUST generate an | 
|  | <literal>InternalServerErrorException</literal>, a subclass of | 
|  | <literal>WebApplicationException</literal> with its status set to 500, and no entity and the client | 
|  | runtime MUST generate a <literal>ProcessingException</literal>. | 
|  | </para> | 
|  | <para> | 
|  | We have successfully found a provider, thus no exception is generated. | 
|  | </para> | 
|  | </step> | 
|  | </stepalternatives> | 
|  | </step> | 
|  | </procedure> | 
|  | <note> | 
|  | <para> | 
|  | JAX-RS 3.x/2.x is incompatible with JAX-RS 1.x in one step of the entity provider selection algorithm. | 
|  | JAX-RS 1.x defines sorting keys priorities in the <xref linkend="mbw.writer.selection.algorithm.sortStep" /> | 
|  | in exactly opposite order. So, in JAX-RS 1.x the keys are defined in the order: primary media type, | 
|  | secondary type declaration distance where custom providers have always precedence to internal providers. | 
|  | If you want to force Jersey to use the algorithm compatible with JAX-RS 1.x, setup the property | 
|  | (to &jersey.server.ResourceConfig; or return from &jaxrs.core.Application; from its | 
|  | <literal>getProperties</literal> method): | 
|  |  | 
|  | <programlisting language="java" linenumbering="unnumbered"><![CDATA[jersey.config.workers.legacyOrdering=true]]></programlisting> | 
|  |  | 
|  | Documentation of this property can be found in the javadoc of &jersey.message.MessageProperties;. | 
|  | </para> | 
|  | </note> | 
|  |  | 
|  | <para> | 
|  | The algorithm for selection of &lit.jaxrs.ext.MessageBodyReader; is similar, including the incompatibility | 
|  | between JAX-RS 3.x/2.x and JAX-RS 1.x and the property to workaround it. The algorithm is defined as follows: | 
|  | </para> | 
|  | <procedure xml:id="mbw.reader.selection.algorithm"> | 
|  | <title>&lit.jaxrs.ext.MessageBodyReader; Selection Algorithm</title> | 
|  | <step> | 
|  | <para> | 
|  | Obtain the media type of the request. If the request does not contain a <literal>Content-Type</literal> | 
|  | header then use <literal>application/octet-stream</literal> media type. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | Identify the Java type of the parameter whose value will be mapped from the entity body. The | 
|  | Java type on the server is the type of the entity parameter of the resource method. On the client | 
|  | it is the <literal>Class</literal> passed to <literal>readFrom</literal> method. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | Select the set of available &lit.jaxrs.ext.MessageBodyReader; providers that support the media type | 
|  | of the request. | 
|  | </para> | 
|  | </step> | 
|  | <step xml:id="mbw.reader.selection.algorithm.selectStep"> | 
|  | <para> | 
|  | Iterate through the selected &lit.jaxrs.ext.MessageBodyReader; classes and, utilizing their | 
|  | <literal>isReadable</literal> method, choose the first &lit.jaxrs.ext.MessageBodyReader; provider that | 
|  | supports the desired combination of Java type/media type/annotations parameters. | 
|  | </para> | 
|  | </step> | 
|  | <step> | 
|  | <para> | 
|  | If <xref linkend="mbw.reader.selection.algorithm.selectStep" /> locates a suitable | 
|  | &lit.jaxrs.ext.MessageBodyReader;, then use its <literal>readFrom</literal> method to map the entity | 
|  | body to the desired Java type. | 
|  | </para> | 
|  | <stepalternatives> | 
|  | <step> | 
|  | <para> | 
|  | Otherwise, the server runtime MUST generate a <literal>NotSupportedException</literal> | 
|  | (HTTP 415 status code) and no entity and the client runtime MUST generate an instance | 
|  | of <literal>ProcessingException</literal>. | 
|  | </para> | 
|  | </step> | 
|  | </stepalternatives> | 
|  | </step> | 
|  | </procedure> | 
|  | </section> | 
|  |  | 
|  | <section> | 
|  | <title>Jersey &lit.jersey.message.MessageBodyWorkers; API</title> | 
|  | <para> | 
|  | In case you need to directly work with JAX-RS entity providers, for example to serialize an entity in your resource | 
|  | method, filter or in a composite entity provider, you would need to perform quite a lot of steps. | 
|  | You would need to choose the appropriate &lit.jaxrs.ext.MessageBodyWriter; based on the type, media type and | 
|  | other parameters. Then you would need to instantiate it, check it by <literal>isWriteable</literal> method and | 
|  | basically perform all the steps that are normally performed by Jersey | 
|  | (see <xref linkend="mbw.reader.selection.algorithm" />). | 
|  | </para> | 
|  | <para> | 
|  | To remove this burden from developers, Jersey exposes a proprietary public API that simplifies the manipulation | 
|  | of entity providers. The API is defined by &jersey.message.MessageBodyWorkers; interface and Jersey provides an | 
|  | implementation that can be injected using the &jaxrs.core.Context; injection annotation. The interface declares | 
|  | methods for selection of most appropriate &lit.jaxrs.ext.MessageBodyReader; and &lit.jaxrs.ext.MessageBodyWriter; | 
|  | based on the rules defined in JAX-RS spec, methods for writing and reading entity that ensure proper and timely | 
|  | invocation of interceptors and other useful methods. | 
|  | </para> | 
|  | <para> | 
|  | See the following example of usage of &lit.jersey.message.MessageBodyWorkers;. | 
|  |  | 
|  | <example> | 
|  | <title>Usage of MessageBodyWorkers interface</title> | 
|  | <programlisting language="java" linenumbering="numbered"><![CDATA[@Path("workers") | 
|  | public static class WorkersResource { | 
|  |  | 
|  | @Context | 
|  | private MessageBodyWorkers workers; | 
|  |  | 
|  | @GET | 
|  | @Produces("application/xml") | 
|  | public String getMyBeanAsString() { | 
|  |  | 
|  | final MyBean myBean = new MyBean("Hello World!", 42); | 
|  |  | 
|  | // buffer into which myBean will be serialized | 
|  | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | 
|  |  | 
|  | // get most appropriate MBW | 
|  | final MessageBodyWriter<MyBean> messageBodyWriter = | 
|  | workers.getMessageBodyWriter(MyBean.class, MyBean.class, | 
|  | new Annotation[]{}, MediaType.APPLICATION_XML_TYPE); | 
|  |  | 
|  | try { | 
|  | // use the MBW to serialize myBean into baos | 
|  | messageBodyWriter.writeTo(myBean, | 
|  | MyBean.class, MyBean.class, new Annotation[] {}, | 
|  | MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<String, Object>(), | 
|  | baos); | 
|  | } catch (IOException e) { | 
|  | throw new RuntimeException( | 
|  | "Error while serializing MyBean.", e); | 
|  | } | 
|  |  | 
|  | final String stringXmlOutput = baos.toString(); | 
|  | // stringXmlOutput now contains XML representation: | 
|  | // "<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | 
|  | // <myBean><anyString>Hello World!</anyString> | 
|  | // <anyNumber>42</anyNumber></myBean>" | 
|  |  | 
|  | return stringXmlOutput; | 
|  | } | 
|  | }]]></programlisting> | 
|  | </example> | 
|  | </para> | 
|  | <para> | 
|  | In the example a resource injects &lit.jersey.message.MessageBodyWorkers; and uses it for selection | 
|  | of the most appropriate &lit.jaxrs.ext.MessageBodyWriter;. Then the writer is utilized to serialize the entity | 
|  | into the buffer as XML document. The <literal>String</literal> content of the buffer is then returned. | 
|  | This will cause that Jersey will not use <literal>MyBeanMessageBodyWriter</literal> | 
|  | to serialize the entity as it is already in the <literal>String</literal> type | 
|  | (<literal>MyBeanMessageBodyWriter</literal> does not support <literal>String</literal>). Instead, a simple | 
|  | <literal>String</literal>-based  &lit.jaxrs.ext.MessageBodyWriter; will be chosen and it will only serialize the | 
|  | <literal>String</literal> with XML to the output entity stream by writing out the bytes of the | 
|  | <literal>String</literal>. | 
|  | </para> | 
|  | <para> | 
|  | Of course, the code in the example does not bring any benefit as the entity could | 
|  | have been serialized by <literal>MyBeanMessageBodyWriter</literal> by Jersey as in previous examples; | 
|  | the purpose of the example was to show how to use &lit.jersey.message.MessageBodyWorkers; in a resource method. | 
|  | </para> | 
|  | </section> | 
|  |  | 
|  | <section> | 
|  | <title>Default Jersey Entity Providers</title> | 
|  |  | 
|  | <para> | 
|  | Jersey internally contains entity providers for these types with combination of media types (in brackets): | 
|  | </para> | 
|  | <simplelist> | 
|  | <member> | 
|  | <literal>byte[]</literal> (<literal>*/*</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.String; (<literal>*/*</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.InputStream; (<literal>*/*</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.Reader; (<literal>*/*</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.File; (<literal>*/*</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jee9.DataSource; (<literal>*/*</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.Source; (<literal>text/xml</literal>, <literal>application/xml</literal> and media types of the form | 
|  | <literal>application/*+xml</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.JAXBElement; (<literal>text/xml</literal>, <literal>application/xml</literal> and media types of the form | 
|  | <literal>application/*+xml</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jaxrs.core.MultivaluedMap; (<literal>application/x-www-form-urlencoded</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jaxrs.core.Form; (<literal>application/x-www-form-urlencoded</literal>) | 
|  | </member> | 
|  | <member> | 
|  | &jaxrs.core.StreamingOutput; ((<literal>*/*</literal>)) - this class can be used as an lightweight | 
|  | &lit.jaxrs.ext.MessageBodyWriter; that can be returned from a resource method | 
|  | </member> | 
|  | <member> | 
|  | &jdk6.Boolean;, &jdk6.Character; and &jdk6.Number; (<literal>text/plain</literal>) - corresponding | 
|  | primitive types supported via boxing/unboxing conversion | 
|  | </member> | 
|  | </simplelist> | 
|  | <para> | 
|  | For other media type supported in jersey please see the <xref linkend="media" /> which describes | 
|  | additional Jersey entity provider extensions for serialization to JSON, XML, serialization of collections, | 
|  | &jersey.media.multipart; and others. | 
|  | </para> | 
|  | </section> | 
|  | </chapter> |