| <?xml version="1.0" standalone="no"?> | |
| <!-- | |
| Copyright (c) 2012, 2023 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 link.moxy "<link linkend='json.moxy'>MOXy</link>" > | |
| <!ENTITY link.json-p "<link linkend='json.json-p'>Java API for JSON Processing (JSON-P)</link>" > | |
| <!ENTITY link.jackson "<link linkend='json.jackson'>Jackson</link>" > | |
| <!ENTITY link.jettison "<link linkend='json.jettison'>Jettison</link>" > | |
| <!ENTITY link.json-b "<link linkend='json.json-b'>Java API for JSON Binding (JSON-B)</link>" > | |
| <!ENTITY link.multipart.client.jersey "<link linkend='multipart.client.jersey'>Client using Jersey API</link>" > | |
| <!ENTITY link.multipart.client.rest "<link linkend='multipart.client.rest'>Client using Jakarta REST API</link>" > | |
| <!ENTITY link.multipart.server.jersey "<link linkend='multipart.server.jersey'>Server using Jersey API</link>" > | |
| <!ENTITY link.multipart.server.rest "<link linkend='multipart.server.rest'>Server using Jakarta REST API</link>" > | |
| <!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: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="media"> | |
| <title>Support for Common Media Type Representations</title> | |
| <section xml:id="json"> | |
| <title>JSON</title> | |
| <para> | |
| Jersey JSON support comes as a set of extension modules where each of these modules contains an implementation of | |
| a &jaxrs.core.Feature; that needs to be registered into your &jaxrs.core.Configurable; instance (client/server). | |
| There are multiple frameworks that provide support for JSON processing and/or JSON-to-Java binding. | |
| The modules listed below provide support for JSON representations by integrating the individual JSON frameworks into | |
| Jersey. At present, Jersey integrates with the following modules to provide JSON support: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| &link.moxy; - JSON binding support via MOXy is a default and preferred way of supporting JSON binding | |
| in your Jersey applications since Jersey 2.0. When JSON MOXy module is on the class-path, Jersey will | |
| automatically discover the module and seamlessly enable JSON binding support via MOXy in your | |
| applications. (See <xref linkend="deployment.autodiscoverable" />.) | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>&link.json-p;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&link.jackson;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&link.jettison;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&link.json-b;</para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <section> | |
| <title>Approaches to JSON Support</title> | |
| <para> | |
| Each of the aforementioned extension modules uses one or more of the three basic approaches available when | |
| working with JSON representations: | |
| <itemizedlist> | |
| <listitem> | |
| <para>POJO based JSON binding support</para> | |
| </listitem> | |
| <listitem> | |
| <para>JAXB based JSON binding support</para> | |
| </listitem> | |
| <listitem> | |
| <para>Low-level JSON parsing & processing support</para> | |
| </listitem> | |
| </itemizedlist> | |
| The first method is pretty generic and allows you to map any Java Object to JSON and vice versa. | |
| The other two approaches limit you in Java types your resource methods could produce and/or consume. | |
| JAXB based approach is useful if you plan to utilize certain JAXB features and support both XML and JSON | |
| representations. The last, low-level, approach gives you the best fine-grained control over the out-coming | |
| JSON data format. | |
| </para> | |
| <section xml:id="json-pojo"> | |
| <title>POJO support</title> | |
| <para>POJO support represents the easiest way to convert your Java Objects to JSON and back.</para> | |
| <para>Media modules that support this approach are &link.moxy;, &link.jackson;, and &link.json-b;</para> | |
| </section> | |
| <section xml:id="json-jaxb"> | |
| <title>JAXB based JSON support</title> | |
| <para> | |
| Taking this approach will save you a lot of time, if you want to easily produce/consume both JSON and XML | |
| data format. With JAXB beans you will be able to use the same Java model to generate JSON as well as XML | |
| representations. | |
| Another advantage is simplicity of working with such a model and availability of the API in Java SE Platform. | |
| JAXB leverages annotated POJOs and these could be handled as simple Java beans. | |
| </para> | |
| <para> | |
| A disadvantage of JAXB based approach could be if you need to work with a very specific JSON format. Then it | |
| might be difficult to find a proper way to get such a format produced and consumed. This is a reason why a | |
| lot of configuration options are provided, so that you can control how JAXB beans get serialized and | |
| de-serialized. The extra configuration options however requires you to learn more details about the framework | |
| you are using. | |
| </para> | |
| <para> | |
| Following is a very simple example of how a JAXB bean could look like. | |
| <example> | |
| <title>Simple JAXB bean implementation</title> | |
| <programlisting language="java" linenumbering="numbered">@XmlRootElement | |
| public class MyJaxbBean { | |
| public String name; | |
| public int age; | |
| public MyJaxbBean() {} // JAXB needs this | |
| public MyJaxbBean(String name, int age) { | |
| this.name = name; | |
| this.age = age; | |
| } | |
| }</programlisting> | |
| </example> | |
| Using the above JAXB bean for producing JSON data format from you resource method, is then as simple as: | |
| <example> | |
| <title>JAXB bean used to generate JSON representation</title> | |
| <programlisting language="java" linenumbering="numbered">@GET | |
| @Produces("application/json") | |
| public MyJaxbBean getMyBean() { | |
| return new MyJaxbBean("Agamemnon", 32); | |
| }</programlisting> | |
| </example> | |
| Notice, that JSON specific mime type is specified in &lit.jaxrs.Produces; annotation, and the method returns | |
| an instance of <literal>MyJaxbBean</literal>, which JAXB is able to process. Resulting JSON in this case | |
| would look like: | |
| <programlisting language="text" linenumbering="unnumbered">{"name":"Agamemnon", "age":"32"}</programlisting> | |
| </para> | |
| <para> | |
| A proper use of JAXB annotations itself enables you to control output JSON format to certain extent. | |
| Specifically, renaming and omitting items is easy to do directly just by using JAXB annotations. | |
| For example, the following example depicts changes in the above mentioned MyJaxbBean that will result in | |
| <literal>{"king":"Agamemnon"}</literal> JSON output. | |
| <example> | |
| <title>Tweaking JSON format using JAXB</title> | |
| <programlisting language="java" linenumbering="numbered">@XmlRootElement | |
| public class MyJaxbBean { | |
| @XmlElement(name="king") | |
| public String name; | |
| @XmlTransient | |
| public int age; | |
| // several lines removed | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>Media modules that support this approach are &link.moxy;, &link.jackson;, &link.jettison;</para> | |
| </section> | |
| <section xml:id="json-lowlevel"> | |
| <title>Low-level based JSON support</title> | |
| <para> | |
| JSON Processing API is a new standard API for parsing and processing JSON structures in similar way to what | |
| SAX and StAX parsers provide for XML. The API is part of Jakarta EE 9 and later. Another such JSON | |
| parsing/processing API is provided by Jettison framework (which is also supported in jakartified environment). | |
| Both APIs provide a low-level access to producing | |
| and consuming JSON data structures. By adopting this low-level approach you would be working with | |
| <literal>JsonObject</literal> (or <literal>JSONObject</literal> respectively) and/or | |
| <literal>JsonArray</literal> (or <literal>JSONArray</literal> respectively) classes when processing your | |
| JSON data representations. | |
| </para> | |
| <para> | |
| The biggest advantage of these low-level APIs is that you will gain full control over the JSON format | |
| produced and consumed. You will also be able to produce and consume very large JSON structures using | |
| streaming JSON parser/generator APIs. | |
| On the other hand, dealing with your data model objects will probably be a lot more complex, compared | |
| to the POJO or JAXB based binding approach. Differences are depicted at the following code snippets. | |
| </para> | |
| <para> | |
| Let's start with JAXB-based approach. | |
| <example> | |
| <title>JAXB bean creation</title> | |
| <programlisting language="java" linenumbering="numbered">MyJaxbBean myBean = new MyJaxbBean("Agamemnon", 32);</programlisting> | |
| </example> | |
| Above you construct a simple JAXB bean, which could be written in JSON as | |
| <literal>{"name":"Agamemnon", "age":32}</literal> | |
| </para> | |
| <para> | |
| Now to build an equivalent <literal>JsonObject</literal>/<literal>JSONObject</literal> (in terms of | |
| resulting JSON expression), you would need several more lines of code. The following example illustrates | |
| how to construct the same JSON data using the standard Jakarta EE 9 JSON-Processing API. | |
| <example> | |
| <title>Constructing a <literal>JsonObject</literal> (JSON-Processing)</title> | |
| <programlisting language="java" linenumbering="numbered">JsonObject myObject = Json.createObjectBuilder() | |
| .add("name", "Agamemnon") | |
| .add("age", 32) | |
| .build();</programlisting> | |
| </example> | |
| And at last, here's how the same work can be done with Jettison API. | |
| <example> | |
| <title>Constructing a <literal>JSONObject</literal> (Jettison)</title> | |
| <programlisting language="java" linenumbering="numbered">JSONObject myObject = new JSONObject(); | |
| try { | |
| myObject.put("name", "Agamemnon"); | |
| myObject.put("age", 32); | |
| } catch (JSONException ex) { | |
| LOGGER.log(Level.SEVERE, "Error ...", ex); | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para> | |
| Media modules that support the low-level JSON parsing and generating approach are &link.json-p; | |
| and &link.jettison;. Unless you have a strong reason for using the non-standard &link.jettison; API, | |
| we recommend you to use the new standard &link.json-p; API instead. | |
| </para> | |
| </section> | |
| </section> | |
| <section xml:id="json.moxy"> | |
| <title>MOXy</title> | |
| <section> | |
| <title>Dependency</title> | |
| <para> | |
| To use MOXy as your JSON provider you need to add &lit.jersey-media-moxy; module to your &lit.pom.xml; file: | |
| <programlisting language="xml" linenumbering="unnumbered"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-moxy</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| If you're not using Maven make sure to have all needed dependencies (see &jersey.media.moxy.deps.link;) on the classpath. | |
| </para> | |
| </section> | |
| <section xml:id="moxy-registration"> | |
| <title>Configure and register</title> | |
| <para> | |
| As stated in the <xref linkend="deployment.autodiscoverable"/> as well as earlier in this chapter, MOXy media | |
| module is one of the modules where you don't need to explicitly register its &lit.jaxrs.core.Feature;s | |
| (&lit.jersey.media.MoxyJsonFeature;) in your client/server &jaxrs.core.Configurable; as this feature is | |
| automatically discovered and registered when you add &lit.jersey-media-moxy; module to your class-path. | |
| </para> | |
| <para> | |
| The auto-discoverable &lit.jersey-media-moxy; module defines a few properties that can be used to control the | |
| automatic registration of &lit.jersey.media.MoxyJsonFeature; (besides the generic | |
| &jersey.common.CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE; an the its client/server variants): | |
| <itemizedlist> | |
| <listitem> | |
| <para>&jersey.common.CommonProperties.MOXY_JSON_FEATURE_DISABLE;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&jersey.server.ServerProperties.MOXY_JSON_FEATURE_DISABLE;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&jersey.client.ClientProperties.MOXY_JSON_FEATURE_DISABLE;</para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <note> | |
| <para> | |
| A manual registration of any other Jersey JSON provider feature (except for &link.json-p;) | |
| disables the automated enabling and configuration of &lit.jersey.media.MoxyJsonFeature;. | |
| </para> | |
| </note> | |
| <para> | |
| To configure &jaxrs.ext.MessageBodyReader;s / &jaxrs.ext.MessageBodyWriter;s provided by MOXy you can simply | |
| create an instance of &jersey.media.MoxyJsonConfig; and set values of needed properties. For most common | |
| properties you can use a particular method to set the value of the property or you can use more generic | |
| methods to set the property: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| &jersey.media.MoxyJsonConfig.property; - sets a property value for both Marshaller and Unmarshaller. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| &jersey.media.MoxyJsonConfig.marshallerProperty; - sets a property value for Marshaller. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| &jersey.media.MoxyJsonConfig.unmarshallerProperty; - sets a property value for Unmarshaller. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| <example> | |
| <title>&jersey.media.MoxyJsonConfig; - Setting properties.</title> | |
| <programlisting language="java">final Map<String, String> namespacePrefixMapper = new HashMap<String, String>(); | |
| namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi"); | |
| final MoxyJsonConfig configuration = new MoxyJsonConfig() | |
| .setNamespacePrefixMapper(namespacePrefixMapper) | |
| .setNamespaceSeparator(':'); | |
| </programlisting> | |
| </example> | |
| In order to make &lit.jersey.media.MoxyJsonConfig; visible for MOXy you need to create and register | |
| &lit.jaxrs.ext.ContextResolver; in your client/server code. | |
| <example> | |
| <title>Creating <literal>ContextResolver<MoxyJsonConfig></literal></title> | |
| <programlisting language="java">final Map<String, String> namespacePrefixMapper = new HashMap<String, String>(); | |
| namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi"); | |
| final MoxyJsonConfig moxyJsonConfig = MoxyJsonConfig() | |
| .setNamespacePrefixMapper(namespacePrefixMapper) | |
| .setNamespaceSeparator(':'); | |
| final ContextResolver<MoxyJsonConfig> jsonConfigResolver = moxyJsonConfig.resolver(); | |
| </programlisting> | |
| </example> | |
| </para> | |
| <para> | |
| Another way to pass configuration properties to the underlying <literal>MOXyJsonProvider</literal> is to set | |
| them directly into your &jaxrs.core.Configurable; instance (see an example below). These are overwritten by | |
| properties set into the &jersey.media.MoxyJsonConfig;. | |
| <example> | |
| <title>Setting properties for MOXy providers into &jaxrs.core.Configurable;</title> | |
| <programlisting language="java">new ResourceConfig() | |
| .property(MarshallerProperties.JSON_NAMESPACE_SEPARATOR, ".") | |
| // further configuration</programlisting> | |
| </example> | |
| </para> | |
| <para> | |
| There are some properties for which Jersey sets the default value when | |
| &jaxrs.ext.MessageBodyReader; / &jaxrs.ext.MessageBodyWriter; from MOXy is used and they are: | |
| <table frame="all"> | |
| <title>Default property values for MOXy &jaxrs.ext.MessageBodyReader; / &jaxrs.ext.MessageBodyWriter;</title> | |
| <tgroup cols="2" align="left"> | |
| <tbody> | |
| <row> | |
| <entry><literal>jakarta.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT</literal></entry> | |
| <entry><literal>false</literal></entry> | |
| </row> | |
| <row> | |
| <entry> | |
| <literal>org.eclipse.persistence.jaxb.JAXBContextProperties#JSON_INCLUDE_ROOT</literal> | |
| </entry> | |
| <entry><literal>false</literal></entry> | |
| </row> | |
| <row> | |
| <entry> | |
| <literal>org.eclipse.persistence.jaxb.MarshallerProperties#JSON_MARSHAL_EMPTY_COLLECTIONS</literal> | |
| </entry> | |
| <entry><literal>true</literal></entry> | |
| </row> | |
| <row> | |
| <entry> | |
| <literal>org.eclipse.persistence.jaxb.JAXBContextProperties#JSON_NAMESPACE_SEPARATOR</literal> | |
| </entry> | |
| <entry><literal>org.eclipse.persistence.oxm.XMLConstants#DOT</literal></entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| <example xml:id="ex-moxy-client"> | |
| <title>Building client with MOXy JSON feature enabled.</title> | |
| <programlisting language="java">final Client client = ClientBuilder.newBuilder() | |
| // The line below that registers MOXy feature can be | |
| // omitted if FEATURE_AUTO_DISCOVERY_DISABLE is | |
| // not disabled. | |
| .register(MoxyJsonFeature.class) | |
| .register(jsonConfigResolver) | |
| .build();</programlisting> | |
| </example> | |
| <example xml:id="ex-moxy-server"> | |
| <title>Creating JAX-RS application with MOXy JSON feature enabled.</title> | |
| <programlisting language="java">// Create JAX-RS application. | |
| final Application application = new ResourceConfig() | |
| .packages("org.glassfish.jersey.examples.jsonmoxy") | |
| // The line below that registers MOXy feature can be | |
| // omitted if FEATURE_AUTO_DISCOVERY_DISABLE is | |
| // not disabled. | |
| .register(MoxyJsonFeature.class) | |
| .register(jsonConfigResolver);</programlisting> | |
| </example> | |
| </section> | |
| <section> | |
| <title>Examples</title> | |
| <para> | |
| Jersey provides a <link xlink:href='&jersey.github.examples.uri;/json-moxy'>JSON MOXy example</link> | |
| on how to use MOXy to consume/produce JSON. | |
| </para> | |
| </section> | |
| </section> | |
| <section xml:id="json.json-p"> | |
| <title>Java API for JSON Processing (JSON-P)</title> | |
| <section> | |
| <title>Dependency</title> | |
| <para> | |
| To use JSON-P as your JSON provider you need to add &lit.jersey-media-json-processing; module to your | |
| &lit.pom.xml; file: | |
| <programlisting language="xml" linenumbering="unnumbered"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-json-processing</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| If you're not using Maven make sure to have all needed dependencies (see &jersey.media.json-processing.deps.link;) | |
| on the class-path. | |
| </para> | |
| </section> | |
| <section xml:id="jsonp-registration"> | |
| <title>Configure and register</title> | |
| <para> | |
| As stated in <xref linkend="deployment.autodiscoverable"/> JSON-Processing media module is one of the | |
| modules where you don't need to explicitly register its | |
| &lit.jaxrs.core.Feature;s (&lit.jersey.media.JsonProcessingFeature;) in your client/server | |
| &jaxrs.core.Configurable; as this feature is automatically discovered and registered when you add | |
| &lit.jersey-media-json-processing; module to your classpath. | |
| </para> | |
| <para> | |
| As for the other modules, &lit.jersey-media-json-processing; has also few properties that can affect the | |
| registration of &lit.jersey.media.JsonProcessingFeature; | |
| (besides &jersey.common.CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE; and the like): | |
| <itemizedlist> | |
| <listitem> | |
| <para>&jersey.common.CommonProperties.JSON_PROCESSING_FEATURE_DISABLE;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&jersey.server.ServerProperties.JSON_PROCESSING_FEATURE_DISABLE;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&jersey.client.ClientProperties.JSON_PROCESSING_FEATURE_DISABLE;</para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| To configure &jaxrs.ext.MessageBodyReader;s / &jaxrs.ext.MessageBodyWriter;s provided by JSON-P you can simply | |
| add values for supported properties into the &jaxrs.core.Configuration; instance (client/server). Currently | |
| supported are these properties: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| <literal>JsonGenerator.PRETTY_PRINTING</literal> | |
| ("<literal>jakarta.json.stream.JsonGenerator.prettyPrinting</literal>") | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <example> | |
| <title>Building client with JSON-Processing JSON feature enabled.</title> | |
| <programlisting language="java">ClientBuilder.newClient(new ClientConfig() | |
| // The line below that registers JSON-Processing feature can be | |
| // omitted if FEATURE_AUTO_DISCOVERY_DISABLE is not disabled. | |
| .register(JsonProcessingFeature.class) | |
| .property(JsonGenerator.PRETTY_PRINTING, true) | |
| );</programlisting> | |
| </example> | |
| <example> | |
| <title>Creating JAX-RS application with JSON-Processing JSON feature enabled.</title> | |
| <programlisting language="java">// Create JAX-RS application. | |
| final Application application = new ResourceConfig() | |
| // The line below that registers JSON-Processing feature can be | |
| // omitted if FEATURE_AUTO_DISCOVERY_DISABLE is not disabled. | |
| .register(JsonProcessingFeature.class) | |
| .packages("org.glassfish.jersey.examples.jsonp") | |
| .property(JsonGenerator.PRETTY_PRINTING, true);</programlisting> | |
| </example> | |
| </section> | |
| <section> | |
| <title>Examples</title> | |
| <para>Jersey provides a | |
| <link xlink:href='&jersey.github.examples.uri;/json-processing-webapp'>JSON Processing example</link> | |
| on how to use JSON-Processing to consume/produce JSON.</para> | |
| </section> | |
| </section> | |
| <section xml:id="json.jackson"> | |
| <title>Jackson (2.x)</title> | |
| <section> | |
| <title>Dependency</title> | |
| <para> | |
| To use Jackson 2.x as your JSON provider you need to add &lit.jersey-media-json-jackson; module to your | |
| &lit.pom.xml; file: | |
| <programlisting language="xml" linenumbering="unnumbered"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-json-jackson</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| If you're not using Maven make sure to have all needed dependencies (see &jersey.media.json-jackson.deps.link;) | |
| on the classpath. | |
| </para> | |
| </section> | |
| <section xml:id="jackson-registration"> | |
| <title>Configure and register</title> | |
| <note> | |
| <para> | |
| Note that namespace for Jackson 2.x is (<literal>com.fasterxml.jackson</literal>). | |
| </para> | |
| </note> | |
| <para> | |
| Jackson JSON processor could be controlled via providing a custom Jackson 2 &jersey.media.ObjectMapper; instance. | |
| This could be handy if you need to redefine the default Jackson behaviour and to fine-tune how your JSON data | |
| structures look like. Detailed description of all Jackson features is out of scope of this guide. The example | |
| below gives you a hint on how to wire your &lit.jersey.media.ObjectMapper; | |
| instance into your Jersey application. | |
| </para> | |
| <para> | |
| Since the 2.36 version of Jersey it is possible to filter (include/exclude) Jackson modules by properties | |
| &jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES; and &jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES; | |
| (with their client/server derivatives). If the &jersey.common.CommonProperties.JSON_JACKSON_ENABLED_MODULES; property is used, | |
| only those named modules will be used for JSON processing. On the other hand if the &jersey.common.CommonProperties.JSON_JACKSON_DISABLED_MODULES; | |
| property is used, those listed modules will be explicitly excluded from processing while other (not listed) will remain. Please note that | |
| the <literal>JaxbAnnotationModule</literal> module is always excluded from processing and this is not configurable. | |
| </para> | |
| <para> | |
| In order to use Jackson as your JSON (JAXB/POJO) provider you need to register &jersey.media.JacksonFeature; | |
| and a &lit.jaxrs.ext.ContextResolver; for &lit.jersey.media.ObjectMapper;, | |
| if needed, in your &jaxrs.core.Configurable; (client/server). | |
| <example> | |
| <title><literal>ContextResolver<ObjectMapper></literal></title> | |
| <programlisting language="java" linenumbering="numbered">@Provider | |
| public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> { | |
| final ObjectMapper defaultObjectMapper; | |
| public MyObjectMapperProvider() { | |
| defaultObjectMapper = createDefaultMapper(); | |
| } | |
| @Override | |
| public ObjectMapper getContext(Class<?> type) { | |
| return defaultObjectMapper; | |
| } | |
| } | |
| private static ObjectMapper createDefaultMapper() { | |
| final ObjectMapper result = new ObjectMapper(); | |
| result.configure(Feature.INDENT_OUTPUT, true); | |
| return result; | |
| } | |
| // ... | |
| }</programlisting> | |
| <para>To view the complete example source code, see | |
| <link xlink:href='&jersey.github.examples.uri;/json-jackson/src/main/java/org/glassfish/jersey/examples/jackson/MyObjectMapperProvider.java'> | |
| MyObjectMapperProvider</link> class from the | |
| <link xlink:href='&jersey.github.examples.uri;/json-jackson'>JSON-Jackson</link> example.</para> | |
| </example> | |
| <example> | |
| <title>Building client with Jackson JSON feature enabled.</title> | |
| <programlisting language="java" linenumbering="numbered">final Client client = ClientBuilder.newBuilder() | |
| .register(MyObjectMapperProvider.class) // No need to register this provider if no special configuration is required. | |
| .register(JacksonFeature.class) | |
| .build();</programlisting> | |
| </example> | |
| <example> | |
| <title>Creating JAX-RS application with Jackson JSON feature enabled.</title> | |
| <programlisting language="java" linenumbering="numbered">// Create JAX-RS application. | |
| final Application application = new ResourceConfig() | |
| .packages("org.glassfish.jersey.examples.jackson") | |
| .register(MyObjectMapperProvider.class) // No need to register this provider if no special configuration is required. | |
| .register(JacksonFeature.class);</programlisting> | |
| </example> | |
| </para> | |
| </section> | |
| <section> | |
| <title>Examples</title> | |
| <para> | |
| Jersey provides <link xlink:href='&jersey.github.examples.uri;/json-jackson'>JSON Jackson (2.x) example</link> | |
| showing how to use Jackson to consume/produce JSON. | |
| </para> | |
| </section> | |
| </section> | |
| <section xml:id="json.jettison"> | |
| <title>Jettison</title> | |
| <para> | |
| JAXB approach for (de)serializing JSON in Jettison module provides, in addition to using pure JAXB, | |
| configuration options that could be set on an &jersey.media.JettisonConfig; instance. The instance could be then | |
| further used to create a &jersey.media.JettisonJaxbContext;, which serves as a main configuration point in this | |
| area. | |
| To pass your specialized &lit.jersey.media.JettisonJaxbContext; to Jersey, you will finally need to implement | |
| a JAXBContext &jaxrs.ext.ContextResolver; (see below). | |
| </para> | |
| <section> | |
| <title>Dependency</title> | |
| <para> | |
| To use Jettison as your JSON provider you need to add &lit.jersey-media-json-jettison; module to your | |
| &lit.pom.xml; file: | |
| <programlisting language="xml" linenumbering="unnumbered"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-json-jettison</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| If you're not using Maven make sure to have all needed dependencies (see &jersey.media.json-jettison.deps.link;) on | |
| the classpath. | |
| </para> | |
| </section> | |
| <section> | |
| <title>JSON Notations</title> | |
| <para> | |
| &lit.jersey.media.JettisonConfig; allows you to use two JSON notations. Each of these notations serializes | |
| JSON in a different way. Following is a list of supported notations: | |
| <itemizedlist> | |
| <listitem> | |
| <para>JETTISON_MAPPED (default notation)</para> | |
| </listitem> | |
| <listitem> | |
| <para>BADGERFISH</para> | |
| </listitem> | |
| </itemizedlist> | |
| You might want to use one of these notations, when working with more complex XML documents. Namely when you | |
| deal with multiple XML namespaces in your JAXB beans. | |
| </para> | |
| <para> | |
| Individual notations and their further configuration options are described below. Rather then explaining | |
| rules for mapping XML constructs into JSON, the notations will be described using a simple example. Following | |
| are JAXB beans, which will be used. | |
| <example> | |
| <title>JAXB beans for JSON supported notations description, simple address bean</title> | |
| <programlisting language="java" linenumbering="numbered">@XmlRootElement | |
| public class Address { | |
| public String street; | |
| public String town; | |
| public Address(){} | |
| public Address(String street, String town) { | |
| this.street = street; | |
| this.town = town; | |
| } | |
| }</programlisting> | |
| </example> | |
| <example> | |
| <title>JAXB beans for JSON supported notations description, contact bean</title> | |
| <programlisting language="java" linenumbering="numbered">@XmlRootElement | |
| public class Contact { | |
| public int id; | |
| public String name; | |
| public List<Address> addresses; | |
| public Contact() {}; | |
| public Contact(int id, String name, List<Address> addresses) { | |
| this.name = name; | |
| this.id = id; | |
| this.addresses = | |
| (addresses != null) ? new LinkedList<Address>(addresses) : null; | |
| } | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para> | |
| Following text will be mainly working with a contact bean initialized with: | |
| <example> | |
| <title>JAXB beans for JSON supported notations description, initialization</title> | |
| <programlisting language="java" linenumbering="numbered">Address[] addresses = {new Address("Long Street 1", "Short Village")}; | |
| Contact contact = new Contact(2, "Bob", Arrays.asList(addresses));</programlisting> | |
| </example> | |
| I.e. contact bean with <literal>id=2</literal>, <literal>name="Bob"</literal> containing | |
| a single address (<literal>street="Long Street 1"</literal>, <literal>town="Short Village"</literal>). | |
| </para> | |
| <para> | |
| All below described configuration options are documented also in api-docs at &jersey.media.JettisonConfig;. | |
| </para> | |
| <section> | |
| <title>Jettison mapped notation</title> | |
| <para> | |
| If you need to deal with various XML namespaces, you will find Jettison <literal>mapped</literal> | |
| notation pretty useful. Lets define a particular namespace for <code>id</code> item: | |
| <programlisting language="java" linenumbering="numbered">... | |
| @XmlElement(namespace="http://example.com") | |
| public int id; | |
| ...</programlisting> | |
| Then you simply configure a mapping from XML namespace into JSON prefix as follows: | |
| <example xml:id="json.jaxb.jettison.mapped.ns.def"> | |
| <title> | |
| XML namespace to JSON mapping configuration for Jettison based <literal>mapped</literal> notation | |
| </title> | |
| <programlisting language="java" linenumbering="numbered">Map<String,String> ns2json = new HashMap<String, String>(); | |
| ns2json.put("http://example.com", "example"); | |
| context = new JettisonJaxbContext( | |
| JettisonConfig.mappedJettison().xml2JsonNs(ns2json).build(), | |
| types);</programlisting> | |
| </example> | |
| Resulting JSON will look like in the example below. | |
| <example> | |
| <title>JSON expression with XML namespaces mapped into JSON</title> | |
| <programlisting language="xml" linenumbering="numbered">{ | |
| "contact":{ | |
| "example.id":2, | |
| "name":"Bob", | |
| "addresses":{ | |
| "street":"Long Street 1", | |
| "town":"Short Village" | |
| } | |
| } | |
| }</programlisting> | |
| </example> | |
| Please note, that <code>id</code> item became <code>example.id</code> based on the XML namespace mapping. | |
| If you have more XML namespaces in your XML, you will need to configure appropriate mapping for all of | |
| them. | |
| </para> | |
| <para> | |
| Another configurable option introduced in Jersey version 2.2 is related to serialization of JSON arrays with Jettison's | |
| mapped notation. When serializing elements representing single item lists/arrays, you might want to utilise | |
| the following Jersey configuration method to explicitly name which elements to treat as arrays no matter what the actual content is. | |
| <example xml:id="json.jaxb.jettison.mapped.array.def"> | |
| <title> | |
| JSON Array configuration for Jettison based <literal>mapped</literal> notation | |
| </title> | |
| <programlisting language="java" linenumbering="numbered">context = new JettisonJaxbContext( | |
| JettisonConfig.mappedJettison().serializeAsArray("name").build(), | |
| types);</programlisting> | |
| </example> | |
| Resulting JSON will look like in the example below, unimportant lines removed for sanity. | |
| <example> | |
| <title>JSON expression with JSON arrays explicitly configured via Jersey</title> | |
| <programlisting language="xml" linenumbering="numbered">{ | |
| "contact":{ | |
| ... | |
| "name":["Bob"], | |
| ... | |
| } | |
| }</programlisting> | |
| </example> | |
| </para> | |
| </section> | |
| <section> | |
| <title>Badgerfish notation</title> | |
| <para> | |
| From JSON and JavaScript perspective, this notation is definitely the worst readable one. | |
| You will probably not want to use it, unless you need to make sure your JAXB beans could be flawlessly | |
| written and read back to and from JSON, without bothering with any formatting configuration, namespaces, | |
| etc. | |
| </para> | |
| <para> | |
| &lit.jersey.media.JettisonConfig; instance using <literal>badgerfish</literal> notation could be built | |
| with | |
| <programlisting language="java">JettisonConfig.badgerFish().build()</programlisting> | |
| and the JSON output JSON will be as follows. | |
| <example> | |
| <title>JSON expression produced using <literal>badgerfish</literal> notation</title> | |
| <programlisting language="xml" linenumbering="numbered">{ | |
| "contact":{ | |
| "id":{ | |
| "$":"2" | |
| }, | |
| "name":{ | |
| "$":"Bob" | |
| }, | |
| "addresses":{ | |
| "street":{ | |
| "$":"Long Street 1" | |
| }, | |
| "town":{ | |
| "$":"Short Village" | |
| } | |
| } | |
| } | |
| }</programlisting> | |
| </example> | |
| </para> | |
| </section> | |
| </section> | |
| <section xml:id="jettison-registration"> | |
| <title>Configure and register</title> | |
| <para> | |
| In order to use Jettison as your JSON (JAXB/POJO) provider you need to register &jersey.media.JettisonFeature; | |
| and a &lit.jaxrs.ext.ContextResolver; for &lit.jaxb.JAXBContext; (if needed) in your &jaxrs.core.Configurable; | |
| (client/server). | |
| <example> | |
| <title><literal>ContextResolver<ObjectMapper></literal></title> | |
| <programlisting language="java">@Provider | |
| public class JaxbContextResolver implements ContextResolver<JAXBContext> { | |
| private final JAXBContext context; | |
| private final Set<Class<?>> types; | |
| private final Class<?>[] cTypes = {Flights.class, FlightType.class, AircraftType.class}; | |
| public JaxbContextResolver() throws Exception { | |
| this.types = new HashSet<Class<?>>(Arrays.asList(cTypes)); | |
| this.context = new JettisonJaxbContext(JettisonConfig.DEFAULT, cTypes); | |
| } | |
| @Override | |
| public JAXBContext getContext(Class<?> objectType) { | |
| return (types.contains(objectType)) ? context : null; | |
| } | |
| }</programlisting> | |
| </example> | |
| <example> | |
| <title>Building client with Jettison JSON feature enabled.</title> | |
| <programlisting language="java">final Client client = ClientBuilder.newBuilder() | |
| .register(JaxbContextResolver.class) // No need to register this provider if no special configuration is required. | |
| .register(JettisonFeature.class) | |
| .build();</programlisting> | |
| </example> | |
| <example> | |
| <title>Creating JAX-RS application with Jettison JSON feature enabled.</title> | |
| <programlisting language="java">// Create JAX-RS application. | |
| final Application application = new ResourceConfig() | |
| .packages("org.glassfish.jersey.examples.jettison") | |
| .register(JaxbContextResolver.class) // No need to register this provider if no special configuration is required. | |
| .register(JettisonFeature.class);</programlisting> | |
| </example> | |
| </para> | |
| </section> | |
| <section> | |
| <title>Examples</title> | |
| <para> | |
| Jersey provides an <link xlink:href='&jersey.github.examples.uri;/json-jettison'>JSON Jettison example</link> | |
| on how to use Jettison to consume/produce JSON. | |
| </para> | |
| </section> | |
| </section> | |
| <section> | |
| <title><literal>@JSONP</literal> - JSON with Padding Support</title> | |
| <para> | |
| Jersey provides out-of-the-box support for <link xlink:href='&wikipedia.uri;JSONP'>JSONP</link> | |
| - JSON with padding. The following conditions has to be met to take advantage of this capability: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| Resource method, which should return wrapped JSON, needs to be annotated with &jersey.server.JSONP; | |
| annotation. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| &jaxrs.ext.MessageBodyWriter; for <literal>application/json</literal> media type, which also accepts | |
| the return type of the resource method, needs to be registered (see <link linkend="json">JSON</link> | |
| section of this chapter). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| User's request has to contain &lit.http.header.Accept; header with one of the JavaScript media types | |
| defined (see below). | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| Acceptable media types compatible with &lit.jersey.server.JSONP; are: <literal>application/javascript</literal>, | |
| <literal>application/x-javascript</literal>, <literal>application/ecmascript</literal>, | |
| <literal>text/javascript</literal>, <literal>text/x-javascript</literal>, <literal>text/ecmascript</literal>, | |
| <literal>text/jscript</literal>. | |
| <example> | |
| <title>Simplest case of using &lit.jersey.server.JSONP;</title> | |
| <programlisting language="java">@GET | |
| @JSONP | |
| @Produces({"application/json", "application/javascript"}) | |
| public JaxbBean getSimpleJSONP() { | |
| return new JaxbBean("jsonp"); | |
| }</programlisting> | |
| </example> | |
| Assume that we have registered a JSON providers and that the <literal>JaxbBean</literal> looks like: | |
| <example> | |
| <title>JaxbBean for @JSONP example</title> | |
| <programlisting language="java">@XmlRootElement | |
| public class JaxbBean { | |
| private String value; | |
| public JaxbBean() {} | |
| public JaxbBean(final String value) { | |
| this.value = value; | |
| } | |
| public String getValue() { | |
| return value; | |
| } | |
| public void setValue(final String value) { | |
| this.value = value; | |
| } | |
| }</programlisting> | |
| </example> | |
| When you send a &lit.http.GET; request with &lit.http.header.Accept; header set to | |
| <literal>application/javascript</literal> you'll get a result entity that look like: | |
| <programlisting language="xml">callback({ | |
| "value" : "jsonp", | |
| })</programlisting> | |
| </para> | |
| <para> | |
| There are, of course, ways to configure wrapping method of the returned entity which defaults to | |
| <literal>callback</literal> as you can see in the previous example. | |
| &lit.jersey.server.JSONP; has two parameters that can be configured: <literal>callback</literal> and | |
| <literal>queryParam</literal>. | |
| <literal>callback</literal> stands for the name of the JavaScript callback function defined by the application. | |
| The second parameter, <literal>queryParam</literal>, defines the name of the query parameter holding the name of | |
| the callback function to be used (if present in the request). Value of <literal>queryParam</literal> defaults to | |
| <literal>__callback</literal> so even if you do not set the name of the query parameter yourself, client can | |
| always affect the result name of the wrapping JavaScript callback method. | |
| <note> | |
| <para> | |
| <literal>queryParam</literal> value (if set) always takes precedence over <literal>callback</literal> | |
| value. | |
| </para> | |
| </note> | |
| </para> | |
| <para> | |
| Lets modify our example a little bit: | |
| <example> | |
| <title>Example of &lit.jersey.server.JSONP; with configured parameters.</title> | |
| <programlisting language="java">@GET | |
| @Produces({"application/json", "application/javascript"}) | |
| @JSONP(callback = "eval", queryParam = "jsonpCallback") | |
| public JaxbBean getSimpleJSONP() { | |
| return new JaxbBean("jsonp"); | |
| }</programlisting> | |
| </example> | |
| And make two requests: | |
| <programlisting>curl -X GET http://localhost:8080/jsonp</programlisting> | |
| will return | |
| <programlisting language="xml">eval({ | |
| "value" : "jsonp", | |
| })</programlisting> | |
| and the | |
| <programlisting>curl -X GET http://localhost:8080/jsonp?jsonpCallback=alert</programlisting> | |
| will return | |
| <programlisting language="xml">alert({ | |
| "value" : "jsonp", | |
| })</programlisting> | |
| </para> | |
| <formalpara> | |
| <title>Example</title> | |
| <para> | |
| You can take a look at a provided | |
| <link xlink:href='&jersey.github.examples.uri;/json-with-padding'>JSON with Padding example</link>. | |
| </para> | |
| </formalpara> | |
| </section> | |
| <section xml:id="json.json-b"> | |
| <title>Java API for JSON Binding (JSON-B)</title> | |
| <para> | |
| Jersey uses &yasson.link; for JSON Binding (JSR-367) implementation. | |
| </para> | |
| <section> | |
| <title>Dependency</title> | |
| <para> | |
| To use JSON-B as your JSON provider you need to add &lit.jersey-media-json-binding; module to your | |
| &lit.pom.xml; file: | |
| <programlisting language="xml" linenumbering="unnumbered"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-json-binding</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| If you're not using Maven make sure to have all needed dependencies | |
| (see &jersey.media.json-binding.deps.link;) on the classpath. | |
| </para> | |
| </section> | |
| <section xml:id="json.jsonb-registration"> | |
| <title>Configure and register</title> | |
| <para> | |
| As stated in <xref linkend="deployment.autodiscoverable"/> JSON-Binding media module is one of the | |
| modules where you don't need to explicitly register its | |
| &lit.jaxrs.core.Feature;s (&lit.jersey.media.JsonBindingFeature;) in your client/server | |
| &jaxrs.core.Configurable; as this feature is automatically discovered and registered when you add | |
| &lit.jersey-media-json-binding; module to your classpath. | |
| </para> | |
| <para> | |
| To use custom preconfigured JSON-B, it is simply possible to register | |
| a &lit.jaxrs.ext.ContextResolver; for &lit.jsonb.Jsonb; in your &jaxrs.core.Configurable; | |
| (client/server) and configure &jsonb.JsonbConfig;. | |
| </para> | |
| <example> | |
| <title><literal>ContextResolver<Jsonb></literal></title> | |
| <programlisting language="java">@Provider | |
| public class JsonbContextResolver implements ContextResolver<Jsonb> { | |
| @Override | |
| public Jsonb getContext(Class>?< type) { | |
| JsonbConfig config = new JsonbConfig(); | |
| // configure JsonbConfig | |
| ... | |
| return JsonbBuilder.create(config); | |
| } | |
| }</programlisting> | |
| </example> | |
| <example> | |
| <title><literal>Register the feature and ContextResolver<Jsonb></literal></title> | |
| <programlisting language="java">ClientBuilder.newClient(new ClientConfig() | |
| // The line below that registers JSON-Binding feature can be | |
| // omitted if FEATURE_AUTO_DISCOVERY_DISABLE is not disabled. | |
| .register(JsonBindingFeature.class) | |
| .register(JsonbContextResolver.class) | |
| );</programlisting> | |
| </example> | |
| <formalpara> | |
| <title>Example</title> | |
| <para> | |
| You can take a look at a provided | |
| <link xlink:href='&jersey.github.examples.uri;/json-binding-webapp'>JSON-B example.</link>. | |
| </para> | |
| </formalpara> | |
| </section> | |
| </section> | |
| <section xml:id="json.configuration"> | |
| <title>Properties for configuring JSON providers</title> | |
| <para> | |
| Apart from using &lit.jaxrs.ext.ContextResolver; for configuring directly the specific JSON provider classes, | |
| Jersey supports additional configuration properties prefixed by <literal>JSON</literal> that are available in | |
| <xref linkend="appendix-properties-message">the appendix.</xref> | |
| </para> | |
| </section> | |
| </section> | |
| <section xml:id="xml"> | |
| <title>XML</title> | |
| <para> | |
| As you probably already know, Jersey uses &lit.jaxrs.ext.MessageBodyWriter;s and &lit.jaxrs.ext.MessageBodyReader;s to | |
| parse incoming requests and create outgoing responses. Every user can create its own representation but... this is not | |
| recommended way how to do things. XML is proven standard for interchanging information, especially in web services. | |
| Jerseys supports low level data types used for direct manipulation and JAXB XML entities. | |
| </para> | |
| <section> | |
| <title xml:id="xml.lowlevel">Low level XML support</title> | |
| <para> | |
| Jersey currently support several low level data types: &jdk7.StreamSource;, &jdk7.SAXSource;, &jdk7.DOMSource; | |
| and &jdk7.org.w3c.dom.Document;. You can use these types as the return type or as a method (resource) parameter. | |
| Lets say we want to test this feature and we have | |
| <link xlink:href='&jersey.github.examples.uri;/helloworld'>helloworld example</link> as a starting point. | |
| All we need to do is add methods (resources) which consumes and produces XML and types mentioned above will be | |
| used. | |
| </para> | |
| <example> | |
| <title>Low level XML test - methods added to <literal>HelloWorldResource.java</literal></title> | |
| <programlisting language="java" linenumbering="numbered">@POST | |
| @Path("StreamSource") | |
| public StreamSource getStreamSource(StreamSource streamSource) { | |
| return streamSource; | |
| } | |
| @POST | |
| @Path("SAXSource") | |
| public SAXSource getSAXSource(SAXSource saxSource) { | |
| return saxSource; | |
| } | |
| @POST | |
| @Path("DOMSource") | |
| public DOMSource getDOMSource(DOMSource domSource) { | |
| return domSource; | |
| } | |
| @POST | |
| @Path("Document") | |
| public Document getDocument(Document document) { | |
| return document; | |
| }</programlisting> | |
| </example> | |
| <para> | |
| Both &lit.jaxrs.ext.MessageBodyWriter; and &lit.jaxrs.ext.MessageBodyReader; are used in this case, all we need is | |
| a &lit.http.POST; request with some XML document as a request entity. To keep this as simple as possible only root | |
| element with no content will be sent: <literal>"<test />"</literal>. You can create JAX-RS client to do that | |
| or use some other tool, for example <literal>curl</literal>: | |
| <informalexample> | |
| <programlisting>curl -v http://localhost:8080/base/helloworld/StreamSource -d "<test/>"</programlisting> | |
| </informalexample> | |
| You should get exactly the same XML from our service as is present in the request; in this case, XML headers are | |
| added to response but content stays. Feel free to iterate through all resources. | |
| </para> | |
| </section> | |
| <section> | |
| <title xml:id="xml.jaxb.xmlRootElement">Getting started with JAXB</title> | |
| <para> | |
| Good start for people which already have some experience with JAXB annotations | |
| is <link xlink:href='&jersey.github.examples.uri;/jaxb'>JAXB example</link>. You can see various use-cases there. | |
| This text is mainly meant for those who don't have prior experience with JAXB. Don't expect that all possible | |
| annotations and their combinations will be covered in this chapter, | |
| <link xlink:href='http://jaxb.java.net'>JAXB (JSR 222 implementation)</link> | |
| is pretty complex and comprehensive. But if you just want to know how you can interchange XML messages with your | |
| REST service, you are looking at the right chapter. | |
| </para> | |
| <para> | |
| Lets start with simple example. Lets say we have class <literal>Planet</literal> and service which produces | |
| "Planets". | |
| </para> | |
| <example> | |
| <title>Planet class</title> | |
| <programlisting language="java" linenumbering="numbered">@XmlRootElement | |
| public class Planet { | |
| public int id; | |
| public String name; | |
| public double radius; | |
| }</programlisting> | |
| </example> | |
| <example> | |
| <title>Resource class</title> | |
| <programlisting language="java" linenumbering="numbered">@Path("planet") | |
| public class Resource { | |
| @GET | |
| @Produces(MediaType.APPLICATION_XML) | |
| public Planet getPlanet() { | |
| final Planet planet = new Planet(); | |
| planet.id = 1; | |
| planet.name = "Earth"; | |
| planet.radius = 1.0; | |
| return planet; | |
| } | |
| }</programlisting> | |
| </example> | |
| <para> | |
| You can see there is some extra annotation declared on <literal>Planet</literal> class, particularly | |
| &jaxb.annotation.XmlRootElement;. This is an JAXB annotation which maps java classes | |
| to XML elements. We don't need to specify anything else, because <literal>Planet</literal> is very simple class | |
| and all fields are public. In this case, XML element name will be derived from the class name or | |
| you can set the name property: <literal>@XmlRootElement(name="yourName")</literal>. | |
| </para> | |
| <para> | |
| Our resource class will respond to <literal>GET /planet</literal> with | |
| <programlisting language="xml"><?xml version="1.0" encoding="UTF-8" standalone="yes"?> | |
| <planet> | |
| <id>1</id> | |
| <name>Earth</name> | |
| <radius>1.0</radius> | |
| </planet></programlisting> | |
| which might be exactly what we want... or not. Or we might not really care, because we | |
| can use JAX-RS client for making requests to this resource and this is easy as: | |
| <programlisting language="java" linenumbering="unnumbered"> | |
| Planet planet = webTarget.path("planet").request(MediaType.APPLICATION_XML_TYPE).get(Planet.class); | |
| </programlisting> | |
| There is pre-created &lit.jaxrs.client.WebTarget; object which points to our applications context root and | |
| we simply add path (in our case its <literal>planet</literal>), accept header (not mandatory, but service could | |
| provide different content based on this header; for example <literal>text/html</literal> can be served for web | |
| browsers) and at the end we specify that we are expecting <literal>Planet</literal> class via &lit.http.GET; | |
| request. | |
| </para> | |
| <para> | |
| There may be need for not just producing XML, we might want to consume it as well. | |
| <example> | |
| <title>Method for consuming Planet</title> | |
| <programlisting language="java" linenumbering="numbered">@POST | |
| @Consumes(MediaType.APPLICATION_XML) | |
| public void setPlanet(Planet planet) { | |
| System.out.println("setPlanet " + planet); | |
| }</programlisting> | |
| </example> | |
| After valid request is made, service will print out string representation of <literal>Planet</literal>, which can | |
| look like <literal>Planet{id=2, name='Mars', radius=1.51}</literal>. With JAX-RS client you can do: | |
| <programlisting language="java" linenumbering="unnumbered"> | |
| webTarget.path("planet").request().post(Entity.xml(planet)); | |
| </programlisting> | |
| </para> | |
| <para> | |
| If there is a need for some other (non default) XML representation, other JAXB annotations would | |
| need to be used. This process is usually simplified by generating java source from XML Schema which is | |
| done by <literal>xjc</literal> which is XML to java compiler and it is part of JAXB. | |
| </para> | |
| </section> | |
| <section> | |
| <title xml:id="xml.jabx.JAXBElement">POJOs</title> | |
| <para> | |
| Sometimes you can't / don't want to add JAXB annotations to source code and you still want to have resources | |
| consuming and producing XML representation of your classes. In this case, &jaxb.JAXBElement; class should help | |
| you. Let's redo planet resource but this time we won't have an &jaxb.annotation.XmlRootElement; annotation on | |
| <literal>Planet</literal> class. | |
| </para> | |
| <example> | |
| <title>Resource class - JAXBElement</title> | |
| <programlisting language="java" linenumbering="numbered">@Path("planet") | |
| public class Resource { | |
| @GET | |
| @Produces(MediaType.APPLICATION_XML) | |
| public JAXBElement<Planet> getPlanet() { | |
| Planet planet = new Planet(); | |
| planet.id = 1; | |
| planet.name = "Earth"; | |
| planet.radius = 1.0; | |
| return new JAXBElement<Planet>(new QName("planet"), Planet.class, planet); | |
| } | |
| @POST | |
| @Consumes(MediaType.APPLICATION_XML) | |
| public void setPlanet(JAXBElement<Planet> planet) { | |
| System.out.println("setPlanet " + planet.getValue()); | |
| } | |
| }</programlisting> | |
| </example> | |
| <para> | |
| As you can see, everything is little more complicated with &lit.jaxb.JAXBElement;. This is because now you need | |
| to explicitly set element name for <literal>Planet</literal> class XML representation. Client side is even more | |
| complicated than server side because you can't do <literal>JAXBElement<Planet></literal> so JAX-RS client | |
| API provides way how to workaround it by declaring subclass of &lit.jaxrs.core.GenericType;. | |
| </para> | |
| <example> | |
| <title>Client side - JAXBElement</title> | |
| <programlisting language="java" linenumbering="numbered">// GET | |
| GenericType<JAXBElement<Planet>> planetType = new GenericType<JAXBElement<Planet>>() {}; | |
| Planet planet = (Planet) webTarget.path("planet").request(MediaType.APPLICATION_XML_TYPE).get(planetType).getValue(); | |
| System.out.println("### " + planet); | |
| // POST | |
| planet = new Planet(); | |
| // ... | |
| webTarget.path("planet").post(new JAXBElement<Planet>(new QName("planet"), Planet.class, planet));</programlisting> | |
| </example> | |
| </section> | |
| <section> | |
| <title xml:id="xml.jaxb.JAXBContext">Using custom JAXBContext</title> | |
| <para>In some scenarios you can take advantage of using custom &jaxb.JAXBContext;. Creating | |
| &lit.jaxb.JAXBContext; is an expensive operation and if you already have one created, same instance | |
| can be used by Jersey. Other possible use-case for this is when you need to set some specific things | |
| to &lit.jaxb.JAXBContext;, for example to set a different class loader. | |
| </para> | |
| <example> | |
| <title>PlanetJAXBContextProvider</title> | |
| <programlisting language="java" linenumbering="numbered">@Provider | |
| public class PlanetJAXBContextProvider implements ContextResolver<JAXBContext> { | |
| private JAXBContext context = null; | |
| public JAXBContext getContext(Class<?> type) { | |
| if (type != Planet.class) { | |
| return null; // we don't support nothing else than Planet | |
| } | |
| if (context == null) { | |
| try { | |
| context = JAXBContext.newInstance(Planet.class); | |
| } catch (JAXBException e) { | |
| // log warning/error; null will be returned which indicates that this | |
| // provider won't/can't be used. | |
| } | |
| } | |
| return context; | |
| } | |
| }</programlisting> | |
| </example> | |
| <para> | |
| Sample above shows simple &lit.jaxb.JAXBContext; creation, all you need to do is put | |
| this &lit.jaxrs.ext.Provider; annotated class somewhere where Jersey can find it. Users sometimes | |
| have problems with using provider classes on client side, so just to reminder - you have to | |
| register them in the client config (client does not do anything like package scanning done by server). | |
| </para> | |
| <example> | |
| <title>Using Provider with JAX-RS client</title> | |
| <programlisting language="java" linenumbering="numbered"> | |
| ClientConfig config = new ClientConfig(); | |
| config.register(PlanetJAXBContextProvider.class); | |
| Client client = ClientBuilder.newClient(config); | |
| </programlisting> | |
| </example> | |
| </section> | |
| <section> | |
| <title>MOXy</title> | |
| <para> | |
| If you want to use <link xlink:href='http://www.eclipse.org/eclipselink/moxy.php'>MOXy</link> as your JAXB | |
| implementation instead of JAXB RI you have two options. You can either use the standard JAXB mechanisms to define | |
| the <literal>JAXBContextFactory</literal> from which a &lit.jaxb.JAXBContext; instance would be obtained (for more | |
| on this topic, read JavaDoc on &jaxb.JAXBContext;) or you can add <literal>jersey-media-moxy</literal> module to | |
| your project and register/configure | |
| <link xlink:href='&jersey.javadoc.uri.prefix;/moxy/xml/MoxyXmlFeature.html'>MoxyXmlFeature</link> class/instance in | |
| the &jaxrs.core.Configurable;. | |
| </para> | |
| <example> | |
| <title>Add <literal>jersey-media-moxy</literal> dependency.</title> | |
| <programlisting language="xml"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-moxy</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| </example> | |
| <example> | |
| <title>Register the <literal>MoxyXmlFeature</literal> class.</title> | |
| <programlisting language="java" linenumbering="numbered">final ResourceConfig config = new ResourceConfig() | |
| .packages("org.glassfish.jersey.examples.xmlmoxy") | |
| .register(MoxyXmlFeature.class);</programlisting> | |
| </example> | |
| <example> | |
| <title>Configure and register an <literal>MoxyXmlFeature</literal> instance.</title> | |
| <programlisting language="java" linenumbering="numbered">// Configure Properties. | |
| final Map<String, Object> properties = new HashMap<String, Object>(); | |
| // ... | |
| // Obtain a ClassLoader you want to use. | |
| final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); | |
| final ResourceConfig config = new ResourceConfig() | |
| .packages("org.glassfish.jersey.examples.xmlmoxy") | |
| .register(new MoxyXmlFeature( | |
| properties, | |
| classLoader, | |
| true, // Flag to determine whether eclipselink-oxm.xml file should be used for lookup. | |
| CustomClassA.class, CustomClassB.class // Classes to be bound. | |
| ));</programlisting> | |
| </example> | |
| </section> | |
| <section xml:id="jaxb.configuration"> | |
| <title>Properties for configuring XML providers</title> | |
| <para> | |
| Apart from using &lit.jaxrs.ext.ContextResolver; for configuring directly the specific JSON provider classes, | |
| Jersey supports additional configuration properties prefixed by <literal>JAXB</literal> and <literal>XML</literal> | |
| that are available in <xref linkend="appendix-properties-message">the appendix.</xref> | |
| </para> | |
| </section> | |
| </section> | |
| <section xml:id="multipart"> | |
| <title>Multipart</title> | |
| <titleabbrev id="multipart.short">Multipart</titleabbrev> | |
| <section> | |
| <title>Overview</title> | |
| <para> | |
| The classes in this module provide an integration of <literal>multipart/*</literal> request and response bodies | |
| in a JAX-RS runtime environment. The set of registered providers is leveraged, in that the content type for a body | |
| part of such a message reuses the same &lit.jaxrs.ext.MessageBodyReader;/&lit.jaxrs.ext.MessageBodyWriter; | |
| implementations as would be used for that content type as a standalone entity. | |
| </para> | |
| <para> | |
| The following list of general MIME MultiPart features is currently supported: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| The <literal>MIME-Version: 1.0</literal> HTTP header is included on generated responses. | |
| It is accepted, but not required, on processed requests. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| A &jaxrs.ext.MessageBodyReader; implementation for consuming MIME MultiPart entities. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| A &lit.jaxrs.ext.MessageBodyWriter; implementation for producing MIME MultiPart entities. | |
| The appropriate &lit.jaxrs.ext.Provider; is used to serialize each body part, based on its media type. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Optional creation of an appropriate <literal>boundary</literal> parameter on a generated | |
| <literal>Content-Type</literal> header, if not already present. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| For more information refer to &jersey.media.multipart;. | |
| </para> | |
| <section> | |
| <title>Dependency</title> | |
| <para> | |
| To use multipart features you need to add &lit.jersey-media-multipart; module to your &lit.pom.xml; file: | |
| <programlisting language="xml"><dependency> | |
| <groupId>org.glassfish.jersey.media</groupId> | |
| <artifactId>jersey-media-multipart</artifactId> | |
| <version>&version;</version> | |
| </dependency></programlisting> | |
| If you're not using Maven make sure to have all needed dependencies (see &jersey.media.multipart.deps.link;) on the | |
| class-path. | |
| </para> | |
| </section> | |
| <section> | |
| <title>Registration</title> | |
| <para> | |
| Prior to Jersey 3.1.0, before you can use the capabilities of the &lit.jersey-media-multipart; | |
| module in your client/server code, you need to register &jersey.media.multipart.MultiPartFeature;. | |
| The multipart feature is supported by Jakarta RESTful Web Services 3.1 multipart API. From Jersey 3.1.0 on, | |
| the &jersey.media.multipart.MultiPartFeature; is no longer required to be registered and it is registered automatically. | |
| </para> | |
| </section> | |
| <section> | |
| <title>Examples</title> | |
| <para>Jersey provides a | |
| <link xlink:href='&jersey.github.examples.uri;/multipart-webapp'>Multipart Web Application Example</link> | |
| on how to use multipart features.</para> | |
| </section> | |
| </section> | |
| <section> | |
| <title>Client</title> | |
| <itemizedlist> | |
| <listitem> | |
| <para>&link.multipart.client.jersey;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&link.multipart.client.rest;</para> | |
| </listitem> | |
| </itemizedlist> | |
| <section xml:id="multipart.client.jersey"> | |
| <title>Client using Jersey API</title> | |
| <para> | |
| &jersey.media.multipart.MultiPart; class (or it's subclasses) can be used as an entry point to use | |
| &lit.jersey-media-multipart; module on the client side. This class represents a | |
| <link xlink:href='&wikipedia.uri;MIME#Multipart_messages'>MIME multipart message</link> and is able | |
| to hold an arbitrary number of &jersey.media.multipart.BodyPart;s. Default media type is | |
| <link xlink:href='&wikipedia.uri;MIME#Mixed'>multipart/mixed</link> | |
| for &lit.jersey.media.multipart.MultiPart; entity and <literal>text/plain</literal> for | |
| &lit.jersey.media.multipart.BodyPart;. | |
| <example> | |
| <title>&lit.jersey.media.multipart.MultiPart; entity</title> | |
| <programlisting language="java">final MultiPart multiPartEntity = new MultiPart() | |
| .bodyPart(new BodyPart().entity("hello")) | |
| .bodyPart(new BodyPart(new JaxbBean("xml"), MediaType.APPLICATION_XML_TYPE)) | |
| .bodyPart(new BodyPart(new JaxbBean("json"), MediaType.APPLICATION_JSON_TYPE)); | |
| final WebTarget target = // Create WebTarget. | |
| final Response response = target | |
| .request() | |
| .post(Entity.entity(multiPartEntity, multiPartEntity.getMediaType()));</programlisting> | |
| </example> | |
| If you send a <literal>multiPartEntity</literal> to the server the entity with <literal>Content-Type</literal> | |
| header in HTTP message would look like: | |
| <example> | |
| <title>&lit.jersey.media.multipart.MultiPart; entity in HTTP message.</title> | |
| <screen language="text" linenumbering="unnumbered"><emphasis>Content-Type: multipart/mixed; boundary=Boundary_1_829077776_1369128119878</emphasis> | |
| --Boundary_1_829077776_1369128119878 | |
| Content-Type: text/plain | |
| hello | |
| --Boundary_1_829077776_1369128119878 | |
| Content-Type: application/xml | |
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?><jaxbBean><value>xml</value></jaxbBean> | |
| --Boundary_1_829077776_1369128119878 | |
| Content-Type: application/json | |
| {"value":"json"} | |
| --Boundary_1_829077776_1369128119878--</screen> | |
| </example> | |
| </para> | |
| <para> | |
| When working with forms (e.g. media type <literal>multipart/form-data</literal>) and various fields in them, | |
| there is a more convenient class to be used - &jersey.media.multipart.FormDataMultiPart;. It automatically sets | |
| the media type for the &lit.jersey.media.multipart.FormDataMultiPart; entity to | |
| <literal>multipart/form-data</literal> and <literal>Content-Disposition</literal> header to | |
| &lit.jersey.media.multipart.FormDataBodyPart; body parts. | |
| <example> | |
| <title>&lit.jersey.media.multipart.FormDataMultiPart; entity</title> | |
| <programlisting language="java">final FormDataMultiPart multipart = new FormDataMultiPart() | |
| .field("hello", "hello") | |
| .field("xml", new JaxbBean("xml")) | |
| .field("json", new JaxbBean("json"), MediaType.APPLICATION_JSON_TYPE); | |
| final WebTarget target = // Create WebTarget. | |
| final Response response = target.request().post(Entity.entity(multipart, multipart.getMediaType()));</programlisting> | |
| </example> | |
| To illustrate the difference when using &lit.jersey.media.multipart.FormDataMultiPart; instead of | |
| &lit.jersey.media.multipart.FormDataBodyPart; you can take a look at the | |
| &lit.jersey.media.multipart.FormDataMultiPart; entity from HTML message: | |
| <example> | |
| <title>&lit.jersey.media.multipart.FormDataMultiPart; entity in HTTP message.</title> | |
| <screen language="text" linenumbering="unnumbered"><emphasis>Content-Type: multipart/form-data; boundary=Boundary_1_511262261_1369143433608</emphasis> | |
| --Boundary_1_511262261_1369143433608 | |
| Content-Type: text/plain | |
| Content-Disposition: form-data; name="hello" | |
| hello | |
| --Boundary_1_511262261_1369143433608 | |
| Content-Type: application/xml | |
| Content-Disposition: form-data; name="xml" | |
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?><jaxbBean><value>xml</value></jaxbBean> | |
| --Boundary_1_511262261_1369143433608 | |
| Content-Type: application/json | |
| Content-Disposition: form-data; name="json" | |
| {"value":"json"} | |
| --Boundary_1_511262261_1369143433608--</screen> | |
| </example> | |
| </para> | |
| <para> | |
| A common use-case for many users is sending files from client to server. For this purpose you can use classes from | |
| <literal>org.glassfish.jersey.jersey.media.multipart</literal> package, such as | |
| &jersey.media.multipart.FileDataBodyPart; or &jersey.media.multipart.StreamDataBodyPart;. | |
| <example> | |
| <title>Multipart - sending files.</title> | |
| <programlisting language="java">// MediaType of the body part will be derived from the file. | |
| final FileDataBodyPart filePart = new FileDataBodyPart("my_pom", new File("pom.xml")); | |
| final FormDataMultiPart multipart = new FormDataMultiPart() | |
| .field("foo", "bar") | |
| .bodyPart(filePart); | |
| final WebTarget target = // Create WebTarget. | |
| final Response response = target.request() | |
| .post(Entity.entity(multipart, multipart.getMediaType()));</programlisting> | |
| </example> | |
| </para> | |
| <warning> | |
| <para> | |
| Do not use &lit.jersey.apache.ApacheConnectorProvider; nor &lit.jersey.grizzly.GrizzlyConnectorProvider; | |
| neither &lit.jersey.jetty.JettyConnectorProvider; connector implementations with Jersey Multipart | |
| features. See <xref linkend="connectors.warning"/> warning for more details. | |
| </para> | |
| </warning> | |
| </section> | |
| <section xml:id="multipart.client.rest"> | |
| <title>Client using Jakarta REST API</title> | |
| <para> | |
| &jaxrs.core.EntityPart; interface can be used as an entry point to use | |
| &lit.jersey-media-multipart; module on the client side. This class represents multipart message is able | |
| to hold an arbitrary number of &jaxrs.core.EntityPart;s. Default media type is | |
| <link xlink:href='&wikipedia.uri;MIME#Mixed'>multipart/form-data</link>. | |
| <example> | |
| <title>Using <literal>EntityPart.Builder</literal> for building an Entity</title> | |
| <programlisting language="java"> | |
| final List<EntityPart> multiPartEntity = new List<>(); | |
| list.add(EntityPart.withName("part-01").content("hello").build()); | |
| list.add(EntityPart.withName("part-01").content(new JaxbBean("xml")).mediaType(MediaType.APPLICATION_XML_TYPE).build()); //same name | |
| list.add(EntityPart.withName("part-02").content(new JaxbBean("json")).mediaType(MediaType.APPLICATION_JSON_TYPE).build()); //other name | |
| final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; | |
| final Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); | |
| final WebTarget target = // Create WebTarget. | |
| final Response response = target.request().post(entity); | |
| </programlisting> | |
| </example> | |
| </para> | |
| <para> | |
| The common use-case for many users is sending files from client to server. It is also covered by | |
| &jaxrs.core.EntityPart;.Builder. | |
| <example> | |
| <title>EntityPart - sending files.</title> | |
| <programlisting language="java">// MediaType of the body part will be derived from the file. | |
| final List<EntityPart> multiPartEntity = new List<>(); | |
| list.add(EntityPart.withFileName("file001.txt").content(new FileInputStream("file001.txt")).build()); | |
| list.add(EntityPart.withFileName("mypom.xml").content(new FileInputStream("pom.xml")).build()); | |
| final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; | |
| final Entity entity = Entity.entity(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE); | |
| final WebTarget target = // Create WebTarget. | |
| final Response response = target.request().post(entity); | |
| </programlisting> | |
| </example> | |
| </para> | |
| </section> | |
| </section> | |
| <section> | |
| <title>Server</title> | |
| <itemizedlist> | |
| <listitem> | |
| <para>&link.multipart.server.jersey;</para> | |
| </listitem> | |
| <listitem> | |
| <para>&link.multipart.server.rest;</para> | |
| </listitem> | |
| </itemizedlist> | |
| <section xml:id="multipart.server.jersey"> | |
| <title>Jersey Server API</title> | |
| <para> | |
| Returning a multipart response from server to client is not much different from the parts described in the client | |
| section above. To obtain a multipart entity, sent by a client, in the application you can use two approaches: | |
| <itemizedlist> | |
| <listitem> | |
| <para>Injecting the whole &jersey.media.multipart.MultiPart; entity.</para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Injecting particular parts of a <literal>form-data</literal> multipart request via | |
| &jersey.media.multipart.FormDataParam; annotation. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <section> | |
| <title>Injecting and returning the &lit.jersey.media.multipart.MultiPart; entity</title> | |
| <para> | |
| Working with &lit.jersey.media.multipart.MultiPart; types is no different from injecting/returning other | |
| entity types. | |
| Jersey provides &lit.jaxrs.ext.MessageBodyReader; for reading the request entity and injecting this entity | |
| into a method parameter of a resource method and &lit.jaxrs.ext.MessageBodyWriter; for writing output entities. | |
| You can expect that either &lit.jersey.media.multipart.MultiPart; or | |
| &lit.jersey.media.multipart.FormDataMultiPart; (<literal>multipart/form-data</literal> media type) object | |
| to be injected into a resource method. | |
| </para> | |
| <example> | |
| <title>Resource method using &lit.jersey.media.multipart.MultiPart; as input parameter / return value.</title> | |
| <programlisting language="java">@POST | |
| @Produces("multipart/mixed") | |
| public MultiPart post(final FormDataMultiPart multiPart) { | |
| return multiPart; | |
| }</programlisting> | |
| </example> | |
| </section> | |
| <section> | |
| <title>Injecting with &lit.jersey.media.multipart.FormDataParam;</title> | |
| <para> | |
| If you just need to bind the named body part(s) of a <literal>multipart/form-data</literal> request | |
| entity body to a resource method parameter you can use &jersey.media.multipart.FormDataParam; annotation. | |
| </para> | |
| <para> | |
| This annotation in conjunction with the media type <literal>multipart/form-data</literal> should be used for | |
| submitting and consuming forms that contain files, non-ASCII data, and binary data. | |
| </para> | |
| <para> | |
| The type of the annotated parameter can be one of the following (for more detailed description see | |
| javadoc to &jersey.media.multipart.FormDataParam;): | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| &lit.jersey.media.multipart.FormDataBodyPart; - The value of the parameter will be the first | |
| named body part or &lit.null; if such a named body part is not present. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| A <literal>List</literal> or <literal>Collection</literal> of | |
| &lit.jersey.media.multipart.FormDataBodyPart;. | |
| The value of the parameter will be one or more named body parts with the same name or | |
| &lit.null; if such a named body part is not present. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| &lit.jersey.media.multipart.FormDataContentDisposition; - The value of the parameter will be the | |
| content disposition of the first named body part part or &lit.null; if such a named body part | |
| is not present. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| A <literal>List</literal> or <literal>Collection</literal> of | |
| &lit.jersey.media.multipart.FormDataContentDisposition;. | |
| The value of the parameter will be one or more content dispositions of the named body parts with the | |
| same name or &lit.null; if such a named body part is not present. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| A type for which a message body reader is available given the media type of the first named body | |
| part. The value of the parameter will be the result of reading using the message body reader given | |
| the type <literal>T</literal>, the media type of the named part, and the bytes of the named body | |
| part as input. | |
| </para> | |
| <para> | |
| If there is no named part present and there is a default value present as declared by | |
| &jaxrs.DefaultValue; then the media type will be set to <literal>text/plain</literal>. | |
| The value of the parameter will be the result of reading using the message body reader given the | |
| type <literal>T</literal>, the media type <literal>text/plain</literal>, and the UTF-8 encoded | |
| bytes of the default value as input. | |
| </para> | |
| <para> | |
| If there is no message body reader available and the type <literal>T</literal> conforms | |
| to a type specified by &jaxrs.FormParam; then processing is performed as specified by | |
| &lit.jaxrs.FormParam;, where the values of the form parameter are <literal>String</literal> | |
| instances produced by reading the bytes of the named body parts utilizing a message body reader | |
| for the <literal>String</literal> type and the media type <literal>text/plain</literal>. | |
| </para> | |
| <para> | |
| If there is no named part present then processing is performed as specified by | |
| &lit.jaxrs.FormParam;. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <example> | |
| <title>Use of &lit.jersey.media.multipart.FormDataParam; annotation</title> | |
| <programlisting language="java">@POST | |
| @Consumes(MediaType.MULTIPART_FORM_DATA) | |
| public String postForm( | |
| @DefaultValue("true") @FormDataParam("enabled") boolean enabled, | |
| @FormDataParam("data") FileData bean, | |
| @FormDataParam("file") InputStream file, | |
| @FormDataParam("file") FormDataContentDisposition fileDisposition) { | |
| // ... | |
| }</programlisting> | |
| </example> | |
| <para> | |
| In the example above the server consumes a <literal>multipart/form-data</literal> request entity body that | |
| contains one optional named body part <literal>enabled</literal> and two required named body parts | |
| <literal>data</literal> and <literal>file</literal>. | |
| </para> | |
| <para> | |
| The optional part <literal>enabled</literal> is processed | |
| as a <literal>boolean</literal> value, if the part is absent then the value will be <literal>true</literal>. | |
| </para> | |
| <para> | |
| The part <literal>data</literal> is processed as a JAXB bean and contains some meta-data about the following | |
| part. | |
| </para> | |
| <para> | |
| The part <literal>file</literal> is a file that is uploaded, this is processed as an | |
| <literal>InputStream</literal>. Additional information about the file from the | |
| <literal>Content-Disposition</literal> header can be accessed by the parameter | |
| <literal>fileDisposition</literal>. | |
| </para> | |
| <tip> | |
| <para>&lit.jersey.media.multipart.FormDataParam; annotation can be also used on fields.</para> | |
| </tip> | |
| </section> | |
| </section> | |
| <section xml:id="multipart.server.rest"> | |
| <title>Server using Jakarta REST API</title> | |
| <para> | |
| Using &jaxrs.core.EntityPart; on the server side is similar to the client side. | |
| Jakarta REST specification allows for | |
| returning a &lit.jaxrs.core.Response; or a &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s. | |
| </para> | |
| <para> | |
| Receiving the &jaxrs.core.EntityPart;s can be done either using &lit.jaxrs.FormParam; annotations and | |
| &lit.jaxrs.core.EntityPart;, &lit.jdk6.InputStream; or &lit.jdk6.String; data-types, or using a | |
| &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s. | |
| </para> | |
| <example> | |
| <title>Use of &lit.jaxrs.FormParam; annotation with &lit.jaxrs.core.EntityPart; &lit.jdk6.InputStream; | |
| and &lit.jdk6.String; types and returning a &lit.jaxrs.core.Response;</title> | |
| <programlisting language="java">@POST | |
| @Path("/postFormVarious") | |
| public Response postFormVarious(@FormParam("name1") EntityPart part1, | |
| @FormParam("name2") InputStream part2, | |
| @FormParam("name3") String part3) throws IOException { | |
| final List<EntityPart> list = new LinkedList<>(); | |
| list.add(EntityPart.withName(part1.getName()) | |
| .content(part1.getContent(String.class) + new String(part2.readAllBytes()) + part3) | |
| .mediaType(MediaType.TEXT_PLAIN_TYPE) | |
| .build()); | |
| final GenericEntity<List<EntityPart>> genericEntity = new GenericEntity<>(list) {}; | |
| return Response.ok(genericEntity, MediaType.MULTIPART_FORM_DATA_TYPE).build(); | |
| } | |
| </programlisting> | |
| </example> | |
| <example> | |
| <title>Receiving a &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s</title> | |
| <programlisting language="java">@POST | |
| @Path("/postListForm") | |
| public String postEntityPartForm(@FormParam("part-0x") List<EntityPart> part) throws IOException { | |
| final String entity = part.get(0).getContent(String.class) + part.get(1).getContent(String.class); | |
| return entity; | |
| } | |
| </programlisting> | |
| </example> | |
| <example> | |
| <title>Returning a &lit.jdk6.List; of &lit.jaxrs.core.EntityPart;s</title> | |
| <programlisting language="java">@GET | |
| @Produces(MediaType.MULTIPART_FORM_DATA) | |
| @Path("/getList") | |
| public List<EntityPart> getList() throws IOException { | |
| final List<EntityPart> list = new LinkedList<>(); | |
| list.add(EntityPart.withName("name1").content("data1").build()); | |
| return list; | |
| } | |
| </programlisting> | |
| </example> | |
| </section> | |
| </section> | |
| </section> | |
| </chapter> |