| <?xml version="1.0"?> | |
| <!-- | |
| Copyright (c) 2010, 2021 Oracle and/or its affiliates. All rights reserved. | |
| This program and the accompanying materials are made available under the | |
| terms of the Eclipse Public License v. 2.0, which is available at | |
| http://www.eclipse.org/legal/epl-2.0. | |
| This Source Code may also be made available under the following Secondary | |
| Licenses when the conditions for such availability set forth in the | |
| Eclipse Public License v. 2.0 are satisfied: GNU General Public License, | |
| version 2 with the GNU Classpath Exception, which is available at | |
| https://www.gnu.org/software/classpath/license.html. | |
| SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | |
| --> | |
| <!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]> | |
| <chapter xmlns="http://docbook.org/ns/docbook" | |
| version="5.0" | |
| xml:lang="en" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xmlns:xi="http://www.w3.org/2001/XInclude" | |
| xmlns:xlink="http://www.w3.org/1999/xlink" | |
| xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd | |
| http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd" | |
| xml:id="representations"> | |
| <title>Representations and Responses</title> | |
| <section xml:id="reps-and-types"> | |
| <title>Representations and Java Types</title> | |
| <para>Previous sections on &jaxrs.Produces; and &jaxrs.Consumes; annotations | |
| referred to media type of an entity representation. Examples above depicted resource | |
| methods that could consume and/or produce String Java type for a number of | |
| different media types. This approach is easy to understand and relatively | |
| straightforward when applied to simple use cases. | |
| </para> | |
| <para>To cover also other cases, handling non-textual data for example or handling data stored in the file system, etc., | |
| JAX-RS implementations are required to support also other kinds of media type | |
| conversions where additional, non-String, Java types are being utilized. Following is a short listing of the Java types | |
| that are supported out of the box with respect to supported media type: | |
| <itemizedlist> | |
| <listitem>All media types (<literal>*/*</literal>) | |
| <itemizedlist> | |
| <listitem><literal>byte[]</literal></listitem> | |
| <listitem><literal>java.lang.String</literal></listitem> | |
| <listitem><literal>java.io.Reader</literal> (inbound only)</listitem> | |
| <listitem><literal>java.io.File</literal></listitem> | |
| <listitem><literal>jakarta.activation.DataSource</literal></listitem> | |
| <listitem><literal>jakarta.ws.rs.core.StreamingOutput</literal> (outbound only)</listitem> | |
| </itemizedlist> | |
| </listitem> | |
| <listitem>XML media types (<literal>text/xml</literal>, <literal>application/xml</literal> and <literal>application/...+xml</literal>) | |
| <itemizedlist> | |
| <listitem><literal>javax.xml.transform.Source</literal></listitem> | |
| <listitem><literal>jakarta.xml.bind.JAXBElement</literal></listitem> | |
| <listitem>Application supplied JAXB classes (types annotated with | |
| <link xlink:href="http://docs.oracle.com/javase/6/docs/api/jakarta.xml.bind/annotation/XmlRootElement.html">@XmlRootElement</link> | |
| or<link xlink:href="http://docs.oracle.com/javase/6/docs/api/jakarta.xml.bind/annotation/XmlType.html">@XmlType</link>)</listitem> | |
| </itemizedlist> | |
| </listitem> | |
| <listitem>Form content (<literal>application/x-www-form-urlencoded</literal>) | |
| <itemizedlist> | |
| <listitem><literal>MultivaluedMap<String,String></literal></listitem> | |
| </itemizedlist> | |
| </listitem> | |
| <listitem>Plain text (<literal>text/plain</literal>) | |
| <itemizedlist> | |
| <listitem><literal>java.lang.Boolean</literal></listitem> | |
| <listitem><literal>java.lang.Character</literal></listitem> | |
| <listitem><literal>java.lang.Number</literal></listitem> | |
| </itemizedlist> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para>Unlike method parameters that are associated with the extraction of | |
| request parameters, the method parameter associated with the | |
| representation being consumed does not require annotating. In other words the | |
| representation (entity) parameter does not require a specific 'entity' annotation. A method parameter | |
| without an annotation is an entity. A maximum of | |
| one such unannotated method parameter may exist since there may only be a | |
| maximum of one such representation sent in a request. | |
| </para> | |
| <para>The representation being produced corresponds to what is returned by | |
| the resource method. For example JAX-RS makes it simple to produce images | |
| that are instance of | |
| <literal>File</literal> | |
| as follows: | |
| </para> | |
| <para> | |
| <example> | |
| <title>Using | |
| <code>File</code> | |
| with a specific media type to produce a response | |
| </title> | |
| <programlisting language="java" linenumbering="numbered">@GET | |
| @Path("/images/{image}") | |
| @Produces("image/*") | |
| public Response getImage(@PathParam("image") String image) { | |
| File f = new File(image); | |
| if (!f.exists()) { | |
| throw new WebApplicationException(404); | |
| } | |
| String mt = new MimetypesFileTypeMap().getContentType(f); | |
| return Response.ok(f, mt).build(); | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>The | |
| <literal>File</literal> type can also be used when consuming a representation (request entity). | |
| In that case a temporary file will be created from the incoming request entity and passed as a | |
| parameter to the resource method. | |
| </para> | |
| <para> | |
| The <literal>Content-Type</literal> response header | |
| (if not set programmatically as described in the next section) | |
| will be automatically set based on the media types declared by &jaxrs.Produces; annotation. | |
| Given the following method, the most acceptable media type is used when multiple output media types are allowed: | |
| </para> | |
| <para> | |
| <programlisting language="java" linenumbering="numbered">@GET | |
| @Produces({"application/xml", "application/json"}) | |
| public String doGetAsXmlOrJson() { | |
| ... | |
| }</programlisting> | |
| If <literal>application/xml</literal> is the most acceptable media type defined | |
| by the request (e.g. by header <literal>Accept: application/xml</literal>), then the | |
| <literal>Content-Type</literal> response header | |
| will be set to <literal>application/xml</literal>. | |
| </para> | |
| </section> | |
| <section> | |
| <title>Building Responses</title> | |
| <para>Sometimes it is necessary to return additional | |
| information in response to a HTTP request. Such information may be built | |
| and returned using &jaxrs.core.Response; and &jaxrs.core.Response.ResponseBuilder;. | |
| For example, a common RESTful pattern for the creation of a new resource | |
| is to support a POST request that returns a 201 (Created) status code and | |
| a | |
| <literal>Location</literal> | |
| header whose value is the URI to the newly | |
| created resource. This may be achieved as follows: | |
| </para> | |
| <para> | |
| <example> | |
| <title>Returning 201 status code and adding | |
| <literal>Location</literal> | |
| header in response to POST request | |
| </title> | |
| <programlisting language="java" linenumbering="numbered">@POST | |
| @Consumes("application/xml") | |
| public Response post(String content) { | |
| URI createdUri = ... | |
| create(content); | |
| return Response.created(createdUri).build(); | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>In the above no representation produced is returned, this can be | |
| achieved by building an entity as part of the response as follows: | |
| </para> | |
| <para> | |
| <example> | |
| <title>Adding an entity body to a custom response</title> | |
| <programlisting language="java" linenumbering="numbered">@POST | |
| @Consumes("application/xml") | |
| public Response post(String content) { | |
| URI createdUri = ... | |
| String createdContent = create(content); | |
| return Response.created(createdUri).entity(Entity.text(createdContent)).build(); | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>Response building provides other functionality such as setting the | |
| entity tag and last modified date of the representation. | |
| </para> | |
| </section> | |
| <section> | |
| <title>WebApplicationException and Mapping Exceptions to Responses</title> | |
| <para>Previous section shows how to return HTTP responses, | |
| that are built up programmatically. | |
| It is possible to use the very same mechanism | |
| to return HTTP errors directly, | |
| e.g. when handling exceptions in a try-catch block. | |
| However, to better align with the Java programming model, | |
| JAX-RS allows to define direct mapping of Java exceptions to HTTP error responses. | |
| </para> | |
| <para>The following example shows throwing | |
| <literal>CustomNotFoundException</literal> | |
| from a resource method in order to return an error HTTP response to the client: | |
| </para> | |
| <para> | |
| <example> | |
| <title>Throwing exceptions to control response</title> | |
| <programlisting language="java" linenumbering="numbered">@Path("items/{itemid}/") | |
| public Item getItem(@PathParam("itemid") String itemid) { | |
| Item i = getItems().get(itemid); | |
| if (i == null) { | |
| throw new CustomNotFoundException("Item, " + itemid + ", is not found"); | |
| } | |
| return i; | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>This exception is an application specific exception that extends &jaxrs.WebApplicationException; | |
| and builds a HTTP response with the 404 status code and an optional | |
| message as the body of the response: | |
| </para> | |
| <para> | |
| <example> | |
| <title>Application specific exception implementation</title> | |
| <programlisting language="java" linenumbering="numbered">public class CustomNotFoundException extends WebApplicationException { | |
| /** | |
| * Create a HTTP 404 (Not Found) exception. | |
| */ | |
| public CustomNotFoundException() { | |
| super(Responses.notFound().build()); | |
| } | |
| /** | |
| * Create a HTTP 404 (Not Found) exception. | |
| * @param message the String that is the entity of the 404 response. | |
| */ | |
| public CustomNotFoundException(String message) { | |
| super(Response.status(Responses.NOT_FOUND). | |
| entity(message).type("text/plain").build()); | |
| } | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>In other cases it may not be appropriate to throw instances of &jaxrs.WebApplicationException;, | |
| or classes that extend &jaxrs.WebApplicationException;, and instead it may be preferable to map an existing exception to a | |
| response. For such cases it is possible to use a custom exception mapping provider. The provider must implement | |
| the &jaxrs.ext.ExceptionMapper; interface. For example, the following | |
| maps the | |
| <link xlink:href="http://docs.oracle.com/javaee/5/api/jakarta.persistence/EntityNotFoundException.html">EntityNotFoundException</link> | |
| to a HTTP 404 (Not Found) response: | |
| </para> | |
| <para> | |
| <example> | |
| <title>Mapping generic exceptions to responses</title> | |
| <programlisting language="java" linenumbering="numbered">@Provider | |
| public class EntityNotFoundMapper implements ExceptionMapper<jakarta.persistence.EntityNotFoundException> { | |
| public Response toResponse(jakarta.persistence.EntityNotFoundException ex) { | |
| return Response.status(404). | |
| entity(ex.getMessage()). | |
| type("text/plain"). | |
| build(); | |
| } | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>The above class is annotated with &jaxrs.ext.Provider;, this declares that the class is of interest to the JAX-RS runtime. Such a | |
| class may be added to the set of classes of the &jaxrs.core.Application; instance that is configured. When an application throws an | |
| <link xlink:href="http://docs.oracle.com/javaee/6/api/jakarta.persistence/EntityNotFoundException.html">EntityNotFoundException</link> | |
| the | |
| <literal>toResponse</literal> | |
| method of the | |
| <literal>EntityNotFoundMapper</literal> | |
| instance will be invoked. | |
| </para> | |
| <para> | |
| Jersey supports extension of the exception mappers. These extended mappers must implement | |
| the <literal>org.glassfish.jersey.spi.ExtendedExceptionMapper</literal> interface. This interface additionally | |
| defines method <literal>isMappable(Throwable)</literal> which will be invoked by the Jersey runtime | |
| when exception is thrown and this provider is considered as mappable based on the exception type. Using this | |
| method the provider can reject mapping of the exception before the method <literal>toResponse</literal> | |
| is invoked. The provider can for example check the exception parameters and based on them return false | |
| and let other provider to be chosen for the exception mapping. | |
| </para> | |
| <para> | |
| Since Jersey 3.1.0 the default <literal>ExceptionMapper</literal> is implemented. | |
| It is required by JAX-RS 3.1 specification (&jaxrs31.exceptionMapperProvider;). | |
| The default behaviour of the mapper is to return a message from an exception caught and set the response status | |
| to 500 (internal server error). In case of a &jaxrs.WebApplicationException; with a response that response is returned. | |
| If response inside the &lit.jaxrs.WebApplicationException; is NULL the exception is being processed according to the | |
| default behaviour. | |
| The Default exception mapper is package private and can not be referenced. Its presence is required only by | |
| JAX-RS 3.1 specification. Processing of the default Exception Mapper occurs at the very end of the exception | |
| processing chain. It is invoked only if nothing else in the chain was invoked before. | |
| </para> | |
| </section> | |
| <section> | |
| <title>Conditional GETs and Returning 304 (Not Modified) Responses</title> | |
| <para>Conditional GETs are a great way to reduce bandwidth, and | |
| potentially improve on the server-side performance, depending on how the information used | |
| to determine conditions is calculated. A well-designed web site may for example return | |
| 304 (Not Modified) responses for many of static images it serves. | |
| </para> | |
| <para>JAX-RS provides support for conditional GETs using the contextual interface &jaxrs.core.Request;. | |
| </para> | |
| <para>The following example shows conditional GET support:</para> | |
| <para> | |
| <example> | |
| <title>Conditional GET support</title> | |
| <programlisting language="java" linenumbering="numbered">public SparklinesResource( | |
| @QueryParam("d") IntegerList data, | |
| @DefaultValue("0,100") @QueryParam("limits") Interval limits, | |
| @Context Request request, | |
| @Context UriInfo ui) { | |
| if (data == null) { | |
| throw new WebApplicationException(400); | |
| } | |
| this.data = data; | |
| this.limits = limits; | |
| if (!limits.contains(data)) { | |
| throw new WebApplicationException(400); | |
| } | |
| this.tag = computeEntityTag(ui.getRequestUri()); | |
| if (request.getMethod().equals("GET")) { | |
| Response.ResponseBuilder rb = request.evaluatePreconditions(tag); | |
| if (rb != null) { | |
| throw new WebApplicationException(rb.build()); | |
| } | |
| } | |
| }</programlisting> | |
| </example> | |
| </para> | |
| <para>The constructor of the | |
| <literal>SparklinesResource</literal> | |
| root | |
| resource class computes an entity tag from the request URI and then calls | |
| the | |
| <link xlink:href="&jaxrs.javadoc.uri;/core/Request.html#evaluatePreconditions(jakarta.ws.rs.core.EntityTag)">request.evaluatePreconditions</link> | |
| with that entity tag. If a client request contains an | |
| <literal>If-None-Match</literal> | |
| header with a value that contains the | |
| same entity tag that was calculated then the | |
| <link xlink:href="&jaxrs.javadoc.uri;/core/Request.html#evaluatePreconditions(jakarta.ws.rs.core.EntityTag)">evaluatePreconditions</link> | |
| returns a pre-filled out response, with the 304 status code and entity tag | |
| set, that may be built and returned. Otherwise, | |
| <link xlink:href="&jaxrs.javadoc.uri;/core/Request.html#evaluatePreconditions(jakarta.ws.rs.core.EntityTag)">evaluatePreconditions</link> | |
| returns | |
| <literal>null</literal> | |
| and the normal response can be | |
| returned. | |
| </para> | |
| <para>Notice that in this example the constructor of a resource class is used | |
| to perform actions that may otherwise have to be duplicated to | |
| be invoked for each resource method. The life cycle of resource classes is per-request | |
| which means that the resource instance is created for each request and therefore | |
| can work with request parameters and for example make changes to the request processing by | |
| throwing an exception as it is shown in this example. | |
| </para> | |
| </section> | |
| </chapter> |