| <?xml version="1.0" standalone="no"?> |
| <!-- |
| |
| Copyright (c) 2012, 2024 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(Files.newInputStream(Path.of("file001.txt"))).build()); |
| list.add(EntityPart.withFileName("mypom.xml").content(Files.newInputStream(Path.of("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.configuration"> |
| <title>Properties for configuring the Multipart</title> |
| <para> |
| There are multiple options that can be used when configuring |
| the multipart. See &jersey.media.multipart.MultiPartProperties; or <xref linkend="appendix-properties-multipart"/> |
| for the possibilities. |
| </para> |
| <para> |
| The options can set in a configuration file specified by the |
| &jersey.media.multipart.MultiPartProperties.MULTI_PART_CONFIG_RESOURCE; property. |
| That is the standard Java properties file. |
| </para> |
| <para> |
| Or the options can be set programmatically, |
| by registering <literal>ContextResolver<MultiPartProperties></literal>. For instance: |
| </para> |
| <programlisting language="java">ResourceConfig resourceConfig = new ResourceConfig(); |
| resourceConfig.register(new MultiPartProperties().bufferThreshold(65535).maxParts(2).resolver());</programlisting> |
| </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> |