| <?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> |
| |
| </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> |