| <?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="jaxrs-resources"> |
| <title>JAX-RS Application, Resources and Sub-Resources</title> |
| |
| <para>This chapter presents an overview of the core JAX-RS concepts - resources and sub-resources.</para> |
| |
| <para>The JAX-RS &jax-rs.version; JavaDoc can be found online <link xlink:href="&jaxrs.release.uri;/apidocs/index.html">here</link>. |
| </para> |
| |
| <para>The JAX-RS &jax-rs.version; specification draft can be found online <link |
| xlink:href="http://jcp.org/en/jsr/summary?id=339">here</link>. |
| </para> |
| |
| <section> |
| <title>Root Resource Classes</title> |
| |
| <para> |
| <emphasis>Root resource classes</emphasis> |
| are POJOs (Plain Old Java Objects) that are annotated with &jaxrs.Path; |
| have at least one method annotated with &jaxrs.Path; or a resource method designator annotation such as &jaxrs.GET;, |
| &jaxrs.PUT;, &jaxrs.POST;, &jaxrs.DELETE;. Resource methods are methods of a resource class annotated with a resource |
| method designator. This section shows how to use Jersey to annotate Java objects to create RESTful web services. |
| </para> |
| |
| <para>The following code example is a very simple example of a root |
| resource class using JAX-RS annotations. The example code shown here is |
| from one of the samples that ships with Jersey, the zip file of which can |
| be found in the maven repository |
| <link xlink:href="http://central.maven.org/maven2/org/glassfish/jersey/examples/helloworld//&version;/">here</link>. |
| </para> |
| <para> |
| <example> |
| <title>Simple hello world root resource class</title> |
| <programlisting language="java" linenumbering="numbered">package org.glassfish.jersey.examples.helloworld; |
| |
| import javax.ws.rs.GET; |
| import javax.ws.rs.Path; |
| import javax.ws.rs.Produces; |
| |
| @Path("helloworld") |
| public class HelloWorldResource { |
| public static final String CLICHED_MESSAGE = "Hello World!"; |
| |
| @GET |
| @Produces("text/plain") |
| public String getHello() { |
| return CLICHED_MESSAGE; |
| } |
| }</programlisting> |
| </example> |
| Let's look at some of the JAX-RS annotations used in this example. |
| </para> |
| |
| <section> |
| <title>@Path</title> |
| |
| <para>The &jaxrs.Path; annotation's value is a relative URI path. In the example above, the Java class will be hosted at the URI path |
| <literal>/helloworld</literal>. This is an extremely simple use of the &jaxrs.Path; annotation. What makes JAX-RS so useful is that you can embed variables in the URIs. |
| </para> |
| |
| <para> |
| <emphasis>URI path templates</emphasis> |
| are URIs with variables embedded within the URI syntax. These variables are substituted at runtime in order for a resource to respond to a request based on the substituted URI. Variables are denoted by curly braces. For example, look at the following &jaxrs.Path; annotation: |
| |
| <programlisting language="java" linenumbering="unnumbered">@Path("/users/{username}")</programlisting> |
| |
| In this type of example, a user will be prompted to enter their name, and then a Jersey web service configured to respond to requests to this URI path template will respond. For example, if the user entered their username as "Galileo", the web service will respond to the following URL: |
| <literal>http://example.com/users/Galileo</literal> |
| </para> |
| |
| <para>To obtain the value of the username variable the &jaxrs.PathParam; may be used on method parameter of a request method, for example: |
| <example> |
| <title>Specifying URI path parameter</title> |
| <programlisting language="java" linenumbering="numbered">@Path("/users/{username}") |
| public class UserResource { |
| |
| @GET |
| @Produces("text/xml") |
| public String getUser(@PathParam("username") String userName) { |
| ... |
| } |
| }</programlisting> |
| </example> |
| If it is required that a user name must only consist of |
| lower and upper case numeric characters then it is possible to declare a |
| particular regular expression, which overrides the default regular |
| expression, "[^/]+", for example: |
| <programlisting language="java">@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")</programlisting> |
| In this type of example the username variable will only match user names that begin with one upper or |
| lower case letter and zero or more alpha numeric characters and the underscore character. If a user name |
| does not match that a 404 (Not Found) response will occur. |
| </para> |
| |
| <para>A &jaxrs.Path; value may or may not begin with a '/', it makes no difference. Likewise, by default, |
| a &jaxrs.Path; value may or may not end in a '/', it makes no difference, and thus request URLs that |
| end or do not end in a '/' will both be matched. |
| </para> |
| </section> |
| |
| <section> |
| <title>@GET, @PUT, @POST, @DELETE, ... (HTTP Methods)</title> |
| |
| <para>&jaxrs.GET;, &jaxrs.PUT;, &jaxrs.POST;, &jaxrs.DELETE; and &jaxrs.HEAD; |
| are |
| <emphasis>resource method designator</emphasis> |
| annotations defined |
| by JAX-RS and which correspond to the similarly named HTTP methods. In |
| the example above, the annotated Java method will process HTTP GET |
| requests. The behavior of a resource is determined by which of the HTTP |
| methods the resource is responding to. |
| </para> |
| |
| <para>The following example is an extract from the storage service |
| sample that shows the use of the PUT method to create or update a |
| storage container: |
| </para> |
| |
| <para> |
| <example> |
| <title>PUT method</title> |
| <programlisting language="java" linenumbering="numbered">@PUT |
| public Response putContainer() { |
| System.out.println("PUT CONTAINER " + container); |
| |
| URI uri = uriInfo.getAbsolutePath(); |
| Container c = new Container(container, uri.toString()); |
| |
| Response r; |
| if (!MemoryStore.MS.hasContainer(c)) { |
| r = Response.created(uri).build(); |
| } else { |
| r = Response.noContent().build(); |
| } |
| |
| MemoryStore.MS.createContainer(c); |
| return r; |
| }</programlisting> |
| </example> |
| By default the JAX-RS runtime will automatically support the methods HEAD and OPTIONS, if not explicitly |
| implemented. For HEAD the runtime will invoke the implemented GET method (if present) and ignore the |
| response entity (if set). A response returned for the OPTIONS method depends on the requested media type |
| defined in the 'Accept' header. The OPTIONS method can return a response with a set of supported |
| resource methods in the 'Allow' header or return |
| a <link xlink:href="http://wadl.java.net/">WADL</link> document. |
| See <link linkend="wadl">wadl section</link> for more information. |
| </para> |
| </section> |
| |
| <section> |
| <title>@Produces</title> |
| |
| <para> |
| The &jaxrs.Produces; annotation is used to specify the MIME media types of representations a resource can |
| produce and send back to the client. In this example, the Java method will produce representations identified |
| by the MIME media type "text/plain". &jaxrs.Produces; can be applied at both the class and method levels. |
| Here's an example: |
| </para> |
| |
| <para> |
| <example> |
| <title>Specifying output MIME type</title> |
| <programlisting language="java" linenumbering="numbered">@Path("/myResource") |
| @Produces("text/plain") |
| public class SomeResource { |
| @GET |
| public String doGetAsPlainText() { |
| ... |
| } |
| |
| @GET |
| @Produces("text/html") |
| public String doGetAsHtml() { |
| ... |
| } |
| }</programlisting> |
| </example> |
| The |
| <literal>doGetAsPlainText</literal> |
| method defaults to the MIME type of the &jaxrs.Produces; annotation at the class level. The |
| <literal>doGetAsHtml</literal> |
| method's &jaxrs.Produces; annotation overrides the class-level &jaxrs.Produces; setting, and specifies that the |
| method can produce HTML rather than plain text. |
| </para> |
| |
| <para>If a resource class is capable of producing more that one MIME |
| media type then the resource method chosen will correspond to the most |
| acceptable media type as declared by the client. More specifically the |
| Accept header of the HTTP request declares what is most acceptable. For |
| example if the Accept header is "<literal>Accept: text/plain</literal>" then the |
| <literal>doGetAsPlainText</literal> |
| method will be invoked. |
| Alternatively if the Accept header is " |
| <literal>Accept: text/plain;q=0.9, text/html</literal>", which declares that the client can accept media types of |
| "text/plain" and "text/html" but prefers the latter, then the |
| <literal>doGetAsHtml</literal> |
| method will be invoked. |
| </para> |
| |
| <para>More than one media type may be declared in the same &jaxrs.Produces; declaration, for example: |
| </para> |
| |
| <para> |
| <example> |
| <title>Using multiple output MIME types</title> |
| <programlisting language="java" linenumbering="numbered">@GET |
| @Produces({"application/xml", "application/json"}) |
| public String doGetAsXmlOrJson() { |
| ... |
| }</programlisting> |
| </example> |
| The |
| <literal>doGetAsXmlOrJson</literal> |
| method will get |
| invoked if either of the media types "application/xml" and |
| "application/json" are acceptable. If both are equally acceptable then |
| the former will be chosen because it occurs first. |
| </para> |
| |
| <para>Optionally, server can also specify the quality factor for individual media types. These are |
| considered if several are equally acceptable by the client. For example:</para> |
| |
| <para> |
| <example> |
| <title>Server-side content negotiation</title> |
| <programlisting language="java" linenumbering="numbered">@GET |
| @Produces({"application/xml; qs=0.9", "application/json"}) |
| public String doGetAsXmlOrJson() { |
| ... |
| }</programlisting> |
| </example> |
| In the above sample, if client accepts both "application/xml" and "application/json" (equally), |
| then a server always sends "application/json", since "application/xml" has a lower quality factor. |
| </para> |
| |
| <para>The examples above refers explicitly to MIME media types for |
| clarity. It is possible to refer to constant values, which may reduce |
| typographical errors, see the constant field values of &jaxrs.core.MediaType;. |
| </para> |
| </section> |
| |
| <section> |
| <title>@Consumes</title> |
| <para>The &jaxrs.Consumes; annotation is used to specify the MIME media types of representations |
| that can be consumed by a resource. The above example can be modified to set the cliched |
| message as follows: |
| </para> |
| |
| <para> |
| <example> |
| <title>Specifying input MIME type</title> |
| <programlisting language="java" linenumbering="numbered">@POST |
| @Consumes("text/plain") |
| public void postClichedMessage(String message) { |
| // Store the message |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>In this example, the Java method will consume representations |
| identified by the MIME media type "text/plain". Notice that the resource |
| method returns void. This means no representation is returned and |
| response with a status code of 204 (No Content) will be returned to the client. |
| </para> |
| |
| <para>&jaxrs.Consumes; can be applied at both the class and the method levels and more than one media type |
| may be declared in the same &jaxrs.Consumes; declaration. |
| </para> |
| </section> |
| </section> |
| |
| <section> |
| <title>Parameter Annotations (@*Param)</title> |
| |
| <para>Parameters of a resource method may be annotated with parameter-based annotations to extract information |
| from a request. One of the previous examples presented the use of &jaxrs.PathParam; to extract a path |
| parameter from the path component of the request URL that matched the path declared in &jaxrs.Path;. |
| </para> |
| |
| <para>&jaxrs.QueryParam; is used to extract query parameters from the Query component of the request URL. |
| The following example is an extract from the sparklines sample: |
| </para> |
| |
| <example> |
| <title>Query parameters</title> |
| <programlisting language="java" linenumbering="numbered">@Path("smooth") |
| @GET |
| public Response smooth( |
| @DefaultValue("2") @QueryParam("step") int step, |
| @DefaultValue("true") @QueryParam("min-m") boolean hasMin, |
| @DefaultValue("true") @QueryParam("max-m") boolean hasMax, |
| @DefaultValue("true") @QueryParam("last-m") boolean hasLast, |
| @DefaultValue("blue") @QueryParam("min-color") ColorParam minColor, |
| @DefaultValue("green") @QueryParam("max-color") ColorParam maxColor, |
| @DefaultValue("red") @QueryParam("last-color") ColorParam lastColor) { |
| ... |
| }</programlisting> |
| </example> |
| |
| <para>If a query parameter "step" exists in the query component of the |
| request URI then the "step" value will be extracted and parsed as a |
| 32 bit signed integer and assigned to the step method parameter. If "step" |
| does not exist then a default value of 2, as declared in the &jaxrs.DefaultValue; |
| annotation, will be assigned to the step method parameter. If the "step" |
| value cannot be parsed as a 32 bit signed integer then a HTTP 404 (Not |
| Found) response is returned. User defined Java types such as |
| <literal>ColorParam</literal> |
| may be used, which as implemented as |
| follows: |
| </para> |
| |
| <example> |
| <title>Custom Java type for consuming request parameters</title> |
| <programlisting language="java" linenumbering="numbered">public class ColorParam extends Color { |
| |
| public ColorParam(String s) { |
| super(getRGB(s)); |
| } |
| |
| private static int getRGB(String s) { |
| if (s.charAt(0) == '#') { |
| try { |
| Color c = Color.decode("0x" + s.substring(1)); |
| return c.getRGB(); |
| } catch (NumberFormatException e) { |
| throw new WebApplicationException(400); |
| } |
| } else { |
| try { |
| Field f = Color.class.getField(s); |
| return ((Color)f.get(null)).getRGB(); |
| } catch (Exception e) { |
| throw new WebApplicationException(400); |
| } |
| } |
| } |
| }</programlisting> |
| </example> |
| |
| <para>In general the Java type of the method parameter may:</para> |
| |
| <orderedlist> |
| <listitem> |
| <para>Be a primitive type;</para> |
| </listitem> |
| |
| <listitem> |
| <para>Have a constructor that accepts a single |
| <literal>String</literal> |
| argument; |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para>Have a static method named |
| <literal>valueOf</literal> |
| or |
| <literal>fromString</literal> |
| that accepts a single |
| <literal>String</literal> |
| argument (see, for example, |
| <literal>Integer.valueOf(String)</literal> |
| and <literal>java.util.UUID.fromString(String)</literal>); |
| </para> |
| </listitem> |
| <listitem> |
| <para>Have a registered implementation of <literal>javax.ws.rs.ext.ParamConverterProvider</literal> JAX-RS |
| extension SPI that returns a <literal>javax.ws.rs.ext.ParamConverter</literal> instance capable of |
| a "from string" conversion for the type. |
| or |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para>Be <literal>List<T></literal>, |
| <literal>Set<T></literal> |
| or |
| <literal>SortedSet<T></literal>, where |
| <literal>T</literal> |
| satisfies 2 or 3 above. The resulting collection is read-only. |
| </para> |
| </listitem> |
| </orderedlist> |
| |
| <para>Sometimes parameters may contain more than one value for the same |
| name. If this is the case then types in 5) may be used to obtain all |
| values. |
| </para> |
| |
| <para>If the &jaxrs.DefaultValue; is not used in conjunction with &jaxrs.QueryParam; |
| and the query parameter is not present in the request then value will be |
| an empty collection for<literal>List</literal>, <literal>Set</literal> or <literal>SortedSet</literal>, |
| &lit.null; for other object types, and the Java-defined default for primitive types. |
| </para> |
| |
| <para>The &jaxrs.PathParam; and the other parameter-based annotations, &jaxrs.MatrixParam;, |
| &jaxrs.HeaderParam;, &jaxrs.CookieParam;, &jaxrs.FormParam; obey the same rules as &jaxrs.QueryParam;. |
| &jaxrs.MatrixParam; extracts information from URL path segments. &jaxrs.HeaderParam; extracts information |
| from the HTTP headers. &jaxrs.CookieParam; extracts information from the cookies declared in cookie related HTTP |
| headers. |
| </para> |
| |
| <para>&jaxrs.FormParam; is slightly special because it extracts information from a request representation that |
| is of the MIME media type |
| <literal>"application/x-www-form-urlencoded"</literal> |
| and conforms to the encoding |
| specified by HTML forms, as described here. This parameter is very useful for extracting information that is |
| POSTed by HTML forms, for example the following extracts the form parameter named "name" from the POSTed form |
| data: |
| </para> |
| |
| <para> |
| <example> |
| <title>Processing POSTed HTML form</title> |
| <programlisting language="java" linenumbering="numbered">@POST |
| @Consumes("application/x-www-form-urlencoded") |
| public void post(@FormParam("name") String name) { |
| // Store the message |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>If it is necessary to obtain a general map of parameter name to |
| values then, for query and path parameters it is possible to do the |
| following: |
| </para> |
| |
| <para> |
| <example> |
| <title>Obtaining general map of URI path and/or query parameters</title> |
| <programlisting language="java" linenumbering="numbered">@GET |
| public String get(@Context UriInfo ui) { |
| MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); |
| MultivaluedMap<String, String> pathParams = ui.getPathParameters(); |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>For header and cookie parameters the following:</para> |
| |
| <para> |
| <example> |
| <title>Obtaining general map of header parameters</title> |
| <programlisting language="java" linenumbering="numbered">@GET |
| public String get(@Context HttpHeaders hh) { |
| MultivaluedMap<String, String> headerParams = hh.getRequestHeaders(); |
| Map<String, Cookie> pathParams = hh.getCookies(); |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>In general &jaxrs.core.Context; can be used to obtain contextual Java types related to the request or response. |
| </para> |
| |
| <para>Because form parameters (unlike others) are part of the message entity, it is possible to do the following:</para> |
| |
| <para> |
| <example> |
| <title>Obtaining general map of form parameters</title> |
| <programlisting language="java" linenumbering="numbered">@POST |
| @Consumes("application/x-www-form-urlencoded") |
| public void post(MultivaluedMap<String, String> formParams) { |
| // Store the message |
| }</programlisting> |
| </example> |
| |
| I.e. you don't need to use the &jaxrs.core.Context; annotation. |
| </para> |
| <para>Another kind of injection is the &jaxrs.BeanParam; which allows to inject the parameters described above into a |
| single bean. A bean annotated with &jaxrs.BeanParam; containing any fields and appropriate |
| <literal>*param</literal> |
| annotation(like &jaxrs.PathParam;) will be initialized with corresponding request values in expected way as if these |
| fields were in the resource class. Then instead of injecting request values like path param into a constructor parameters |
| or class fields the &jaxrs.BeanParam; can be used to inject such a bean into a resource or resource method. The |
| &jaxrs.BeanParam; is used this way to aggregate more request parameters into a single bean. |
| </para> |
| <example> |
| <title>Example of the bean which will be used as &jaxrs.BeanParam; |
| </title> |
| <programlisting language="java" linenumbering="numbered">public class MyBeanParam { |
| @PathParam("p") |
| private String pathParam; |
| |
| @MatrixParam("m") |
| @Encoded |
| @DefaultValue("default") |
| private String matrixParam; |
| |
| @HeaderParam("header") |
| private String headerParam; |
| |
| private String queryParam; |
| |
| public MyBeanParam(@QueryParam("q") String queryParam) { |
| this.queryParam = queryParam; |
| } |
| |
| public String getPathParam() { |
| return pathParam; |
| } |
| ... |
| }</programlisting> |
| </example> |
| <example> |
| <title>Injection of MyBeanParam as a method parameter:</title> |
| |
| <programlisting language="java" linenumbering="numbered">@POST |
| public void post(@BeanParam MyBeanParam beanParam, String entity) { |
| final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p" |
| ... |
| }</programlisting> |
| </example> |
| <para>The example shows aggregation of injections &jaxrs.PathParam;, &jaxrs.QueryParam; &jaxrs.MatrixParam; |
| and &jaxrs.HeaderParam; into one single bean. The rules for injections inside the bean are the same as described above |
| for these injections. The &jaxrs.DefaultValue; is used to define the default value for matrix parameter matrixParam. |
| Also the &jaxrs.Encoded; annotation has the same behaviour as if it were used for injection in the resource method |
| directly. Injecting the bean parameter into @Singleton resource class fields is not allowed (injections into method |
| parameter must be used instead). |
| </para> |
| <para>&jaxrs.BeanParam; can contain all parameters injections |
| (&jaxrs.PathParam;, &jaxrs.QueryParam;, &jaxrs.MatrixParam;, &jaxrs.HeaderParam;, |
| &jaxrs.CookieParam;, &jaxrs.FormParam;). More |
| beans can be injected into one resource or method parameters even if they inject the same request values. For example |
| the following is possible: |
| </para> |
| <example> |
| <title>Injection of more beans into one resource methods:</title> |
| |
| <programlisting language="java" linenumbering="numbered">@POST |
| public void post(@BeanParam MyBeanParam beanParam, @BeanParam AnotherBean anotherBean, @PathParam("p") pathParam, |
| String entity) { |
| // beanParam.getPathParam() == pathParam |
| ... |
| }</programlisting> |
| </example> |
| |
| </section> |
| |
| <section> |
| <title>Sub-resources</title> |
| |
| <para>&jaxrs.Path; may be used on classes and such classes are referred to as root resource classes. &jaxrs.Path; |
| may also be used on methods of root resource classes. This enables common functionality for a number of resources |
| to be grouped together and potentially reused. |
| </para> |
| |
| <para>The first way &jaxrs.Path; may be used is on resource methods and such methods are referred to as |
| <emphasis>sub-resource methods</emphasis>. The following example shows the method signatures for a root |
| resource class from the jmaki-backend sample: |
| </para> |
| |
| <para> |
| <example> |
| <title>Sub-resource methods</title> |
| <programlisting language="java" linenumbering="numbered">@Singleton |
| @Path("/printers") |
| public class PrintersResource { |
| |
| @GET |
| @Produces({"application/json", "application/xml"}) |
| public WebResourceList getMyResources() { ... } |
| |
| @GET @Path("/list") |
| @Produces({"application/json", "application/xml"}) |
| public WebResourceList getListOfPrinters() { ... } |
| |
| @GET @Path("/jMakiTable") |
| @Produces("application/json") |
| public PrinterTableModel getTable() { ... } |
| |
| @GET @Path("/jMakiTree") |
| @Produces("application/json") |
| public TreeModel getTree() { ... } |
| |
| @GET @Path("/ids/{printerid}") |
| @Produces({"application/json", "application/xml"}) |
| public Printer getPrinter(@PathParam("printerid") String printerId) { ... } |
| |
| @PUT @Path("/ids/{printerid}") |
| @Consumes({"application/json", "application/xml"}) |
| public void putPrinter(@PathParam("printerid") String printerId, Printer printer) { ... } |
| |
| @DELETE @Path("/ids/{printerid}") |
| public void deletePrinter(@PathParam("printerid") String printerId) { ... } |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>If the path of the request URL is "printers" then the resource methods not annotated with &jaxrs.Path; |
| will be selected. If the request path of the request URL is "printers/list" then first the root resource class |
| will be matched and then the sub-resource methods that match "list" will be selected, which in this case |
| is the sub-resource method <literal>getListOfPrinters</literal>. So, in this example hierarchical matching |
| on the path of the request URL is performed. |
| </para> |
| |
| <para>The second way &jaxrs.Path; may be used is on methods |
| <emphasis role="bold">not</emphasis> |
| annotated |
| with resource method designators such as &jaxrs.GET; or &jaxrs.POST;. Such methods are referred to as |
| <emphasis>sub-resource locators</emphasis>. The following example shows the method signatures for |
| a root resource class and a resource class from the optimistic-concurrency sample: |
| </para> |
| |
| <para> |
| <example> |
| <title>Sub-resource locators</title> |
| <programlisting language="java" linenumbering="numbered">@Path("/item") |
| public class ItemResource { |
| @Context UriInfo uriInfo; |
| |
| @Path("content") |
| public ItemContentResource getItemContentResource() { |
| return new ItemContentResource(); |
| } |
| |
| @GET |
| @Produces("application/xml") |
| public Item get() { ... } |
| } |
| } |
| |
| public class ItemContentResource { |
| |
| @GET |
| public Response get() { ... } |
| |
| @PUT |
| @Path("{version}") |
| public void put(@PathParam("version") int version, |
| @Context HttpHeaders headers, |
| byte[] in) { |
| ... |
| } |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>The root resource class |
| <literal>ItemResource</literal> |
| contains the |
| sub-resource locator method |
| <literal>getItemContentResource</literal> |
| that |
| returns a new resource class. If the path of the request URL is |
| "item/content" then first of all the root resource will be matched, then |
| the sub-resource locator will be matched and invoked, which returns an |
| instance of the |
| <literal>ItemContentResource</literal> |
| resource class. |
| Sub-resource locators enable reuse of resource classes. A method can be annotated with the |
| &jaxrs.Path; annotation with empty path (<literal>@Path("/")</literal> or <literal>@Path("")</literal>) which |
| means that the sub resource locator is matched for the path of the enclosing resource (without sub-resource path). |
| </para> |
| <para> |
| <example> |
| <title>Sub-resource locators with empty path</title> |
| <programlisting language="java" linenumbering="numbered">@Path("/item") |
| public class ItemResource { |
| |
| @Path("/") |
| public ItemContentResource getItemContentResource() { |
| return new ItemContentResource(); |
| } |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>In the example above the sub-resource locator method <literal>getItemContentResource</literal> |
| is matched for example for request path "/item/locator" or even for only "/item". |
| </para> |
| |
| <para>In addition the processing of resource classes returned by |
| sub-resource locators is performed at runtime thus it is possible to |
| support polymorphism. A sub-resource locator may return different |
| sub-types depending on the request (for example a sub-resource locator |
| could return different sub-types dependent on the role of the principle |
| that is authenticated). So for example the following sub resource locator is valid: |
| </para> |
| <para> |
| <example> |
| <title>Sub-resource locators returning sub-type</title> |
| <programlisting language="java" linenumbering="numbered">@Path("/item") |
| public class ItemResource { |
| |
| @Path("/") |
| public Object getItemContentResource() { |
| return new AnyResource(); |
| } |
| }</programlisting> |
| </example> |
| </para> |
| |
| |
| <para>Note that the runtime will not manage the life-cycle or perform any |
| field injection onto instances returned from sub-resource locator methods. |
| This is because the runtime does not know what the life-cycle of the |
| instance is. If it is required that the runtime manages the sub-resources |
| as standard resources the <literal>Class</literal> should be returned |
| as shown in the following example: |
| </para> |
| <para> |
| <example> |
| <title>Sub-resource locators created from classes</title> |
| <programlisting language="java" linenumbering="numbered">import javax.inject.Singleton; |
| |
| @Path("/item") |
| public class ItemResource { |
| @Path("content") |
| public Class<ItemContentSingletonResource> getItemContentResource() { |
| return ItemContentSingletonResource.class; |
| } |
| } |
| |
| @Singleton |
| public class ItemContentSingletonResource { |
| // this class is managed in the singleton life cycle |
| }</programlisting> |
| </example> |
| </para> |
| |
| |
| |
| <para>JAX-RS resources are managed in per-request scope by default which means that |
| new resource is created for each request. |
| In this example the <literal>javax.inject.Singleton</literal> annotation says |
| that the resource will be managed as singleton and not in request scope. |
| The sub-resource locator method returns a class which means that the runtime |
| will managed the resource instance and its life-cycle. If the method would return instance instead, |
| the <literal>Singleton</literal> annotation would have no effect and the returned instance |
| would be used. |
| </para> |
| |
| <para>The sub resource locator can also return a <emphasis>programmatic resource model</emphasis>. See <link |
| linkend="resource-builder">resource builder section</link> for information of how the programmatic resource |
| model is constructed. The following example shows very simple resource returned from the sub-resource locator method. |
| </para> |
| |
| |
| <para> |
| <example> |
| <title>Sub-resource locators returning resource model</title> |
| <programlisting language="java" linenumbering="numbered">import org.glassfish.jersey.server.model.Resource; |
| |
| @Path("/item") |
| public class ItemResource { |
| |
| @Path("content") |
| public Resource getItemContentResource() { |
| return Resource.from(ItemContentSingletonResource.class); |
| } |
| }</programlisting> |
| </example> |
| </para> |
| <para>The code above has exactly the same effect as previous example. <literal>Resource</literal> is a resource |
| simple resource constructed from <literal>ItemContentSingletonResource</literal>. More complex programmatic |
| resource can be returned as long they are valid resources. |
| </para> |
| |
| </section> |
| |
| |
| <section> |
| <title>Life-cycle of Root Resource Classes</title> |
| |
| <para>By default the life-cycle of root resource classes is per-request which, |
| namely that a new instance of a root resource class is created every time |
| the request URI path matches the root resource. This makes for a very |
| natural programming model where constructors and fields can be utilized |
| (as in the previous section showing the constructor of the |
| <literal>SparklinesResource</literal> |
| class) without concern for multiple |
| concurrent requests to the same resource. |
| </para> |
| |
| <para>In general this is unlikely to be a cause of performance issues. |
| Class construction and garbage collection of JVMs has vastly improved over |
| the years and many objects will be created and discarded to serve and |
| process the HTTP request and return the HTTP response. |
| </para> |
| |
| <para>Instances of singleton root resource classes can be declared by an instance of &jaxrs.core.Application;. |
| </para> |
| |
| |
| |
| <para>Jersey supports two further life-cycles using Jersey specific annotations.</para> |
| |
| <table frame="all"> |
| <title>Resource scopes</title> |
| <tgroup cols="4"> |
| <colspec colwidth="1*" /> |
| <colspec colwidth="1*" /> |
| <colspec colwidth="2*" /> |
| <colspec colwidth="5*" /> |
| <thead> |
| <row> |
| <entry>Scope</entry> |
| <entry>Annotation</entry> |
| <entry>Annotation full class name</entry> |
| <entry>Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row><entry>Request scope</entry><entry>@RequestScoped (or none)</entry> |
| <entry>org.glassfish.jersey.process.internal.RequestScoped</entry> |
| <entry><emphasis>Default lifecycle </emphasis> (applied when no annotation is present). In this scope |
| the resource instance is created for each new request and used for processing of this request. If the |
| resource is used more than one time in the request processing, always the same instance will be used. |
| This can happen when a resource is a sub resource and is returned more times during the matching. In this |
| situation only one instance will serve the requests.</entry></row> |
| <row><entry>Per-lookup scope</entry><entry>@PerLookup</entry> |
| <entry>org.glassfish.hk2.api.PerLookup</entry> |
| <entry>In this scope |
| the resource instance is created every time it is needed for the processing even it handles |
| the same request.</entry></row> |
| <row><entry>Singleton</entry><entry>@Singleton</entry> |
| <entry>javax.inject.Singleton</entry> |
| <entry>In this scope there is only one instance per jax-rs application. Singleton resource can be either |
| annotated with @Singleton and its class can be registered using the instance of |
| &jaxrs.core.Application;. You can also create singletons by registering singleton instances |
| into &jaxrs.core.Application;.</entry></row> |
| </tbody> |
| </tgroup> |
| </table> |
| </section> |
| |
| <section> |
| <title>Rules of Injection</title> |
| |
| <para>Previous sections have presented examples of annotated types, mostly |
| annotated method parameters but also annotated fields of a class, for the |
| injection of values onto those types. |
| </para> |
| |
| <para>This section presents the rules of injection of values on annotated |
| types. Injection can be performed on fields, constructor parameters, |
| resource/sub-resource/sub-resource locator method parameters and bean |
| setter methods. The following presents an example of all such injection |
| cases: |
| </para> |
| |
| <para> |
| <example> |
| <title>Injection</title> |
| <programlisting language="java" linenumbering="numbered">@Path("{id:\\d+}") |
| public class InjectedResource { |
| // Injection onto field |
| @DefaultValue("q") @QueryParam("p") |
| private String p; |
| |
| // Injection onto constructor parameter |
| public InjectedResource(@PathParam("id") int id) { ... } |
| |
| // Injection onto resource method parameter |
| @GET |
| public String get(@Context UriInfo ui) { ... } |
| |
| // Injection onto sub-resource resource method parameter |
| @Path("sub-id") |
| @GET |
| public String get(@PathParam("sub-id") String id) { ... } |
| |
| // Injection onto sub-resource locator method parameter |
| @Path("sub-id") |
| public SubResource getSubResource(@PathParam("sub-id") String id) { ... } |
| |
| // Injection using bean setter method |
| @HeaderParam("X-header") |
| public void setHeader(String header) { ... } |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para>There are some restrictions when injecting on to resource classes |
| with a life-cycle of singleton scope. In such cases the class fields or |
| constructor parameters cannot be injected with request specific parameters. So, for example |
| the following is not allowed.</para> |
| |
| <para> |
| <example> |
| <title>Wrong injection into a singleton scope</title> |
| <programlisting language="java" linenumbering="numbered">@Path("resource") |
| @Singleton |
| public static class MySingletonResource { |
| |
| @QueryParam("query") |
| String param; // WRONG: initialization of application will fail as you cannot |
| // inject request specific parameters into a singleton resource. |
| |
| @GET |
| public String get() { |
| return "query param: " + param; |
| } |
| }</programlisting> |
| </example> |
| </para> |
| <para> |
| The example above will cause validation failure during application initialization as singleton |
| resources cannot inject request specific parameters. The same example would fail if the query |
| parameter would be injected into constructor parameter of such a singleton. In other words, if you |
| wish one resource instance to server more requests (in the same time) it cannot be bound |
| to a specific request parameter. |
| </para> |
| <para> |
| The exception exists for specific request objects which can injected even into |
| constructor or class fields. For these objects the runtime will inject proxies |
| which are able to simultaneously server more request. These request objects are |
| <literal>HttpHeaders</literal>, <literal>Request</literal>, <literal>UriInfo</literal>, |
| <literal>SecurityContext</literal>. These proxies can be injected using the &jaxrs.core.Context; |
| annotation. The following example shows injection of proxies into the singleton resource class. |
| </para> |
| |
| <para> |
| <example> |
| <title>Injection of proxies into singleton</title> |
| <programlisting language="java" linenumbering="numbered">@Path("resource") |
| @Singleton |
| public static class MySingletonResource { |
| @Context |
| Request request; // this is ok: the proxy of Request will be injected into this singleton |
| |
| public MySingletonResource(@Context SecurityContext securityContext) { |
| // this is ok too: the proxy of SecurityContext will be injected |
| } |
| |
| @GET |
| public String get() { |
| return "query param: " + param; |
| } |
| }</programlisting> |
| </example> |
| </para> |
| |
| <para> |
| To summarize the injection can be done into the following constructs: |
| </para> |
| <table frame="all"> |
| <title>Overview of injection types</title> |
| <tgroup cols="2"> |
| <colspec colwidth="1*" /> |
| <colspec colwidth="5*" /> |
| <thead> |
| <row> |
| <entry>Java construct</entry> |
| <entry>Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry>Class fields</entry> |
| <entry> |
| Inject value directly into the field of the class. The field can be private |
| and must not be final. Cannot be used in Singleton scope except proxiable types mentioned above. |
| </entry> |
| </row> |
| <row> |
| <entry>Constructor parameters</entry> |
| <entry> |
| The constructor will be invoked with injected values. If more |
| constructors exists the one with the most injectable parameters will be invoked. |
| Cannot be used in Singleton scope except proxiable types mentioned above. |
| </entry> |
| </row> |
| <row> |
| <entry>Resource methods</entry> |
| <entry> |
| The resource methods (these annotated with @GET, @POST, ...) can contain |
| parameters that can be injected when the resource method is executed. |
| Can be used in any scope. |
| </entry> |
| </row> |
| <row> |
| <entry>Sub resource locators</entry> |
| <entry> |
| The sub resource locators (methods annotated with @Path but not @GET, @POST, ...) |
| can contain parameters that can be injected when the resource method is executed. |
| Can be used in any scope. |
| </entry> |
| </row> |
| <row> |
| <entry>Setter methods</entry> |
| <entry> |
| Instead of injecting values directly into field the value can be injected into the |
| setter method which will initialize the field. This injection can be used only with &jaxrs.core.Context; |
| annotation. This means |
| it cannot be used for example for injecting of query params but it can be used for injections of |
| request. The setters will be called after the object creation and |
| only once. The name of the method does not necessary have a setter pattern. Cannot be used |
| in Singleton scope except proxiable types mentioned above. |
| </entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </table> |
| |
| <para> |
| The following example shows all possible java constructs into which the values can be injected. |
| |
| <example> |
| <title>Example of possible injections</title> |
| <programlisting language="java" linenumbering="numbered">@Path("resource") |
| public static class SummaryOfInjectionsResource { |
| @QueryParam("query") |
| String param; // injection into a class field |
| |
| |
| @GET |
| public String get(@QueryParam("query") String methodQueryParam) { |
| // injection into a resource method parameter |
| return "query param: " + param; |
| } |
| |
| @Path("sub-resource-locator") |
| public Class<SubResource> subResourceLocator(@QueryParam("query") String subResourceQueryParam) { |
| // injection into a sub resource locator parameter |
| return SubResource.class; |
| } |
| |
| public SummaryOfInjectionsResource(@QueryParam("query") String constructorQueryParam) { |
| // injection into a constructor parameter |
| } |
| |
| |
| @Context |
| public void setRequest(Request request) { |
| // injection into a setter method |
| System.out.println(request != null); |
| } |
| } |
| |
| public static class SubResource { |
| @GET |
| public String get() { |
| return "sub resource"; |
| } |
| }</programlisting> |
| </example> |
| </para> |
| |
| |
| <para>The &jaxrs.FormParam; annotation is special and may only be utilized on resource and sub-resource methods. |
| This is because it extracts information from a request entity. |
| </para> |
| </section> |
| |
| <section> |
| <title>Use of @Context</title> |
| |
| <para>Previous sections have introduced the use of &jaxrs.core.Context;. Chapter "Context" in the JAX-RS |
| specification presents all the standard JAX-RS Java types that may be used with &jaxrs.core.Context;. |
| </para> |
| |
| <para>When deploying a JAX-RS application using servlet then |
| <link xlink:href="http://docs.oracle.com/javaee/5/api/javax/servlet/ServletConfig.html">ServletConfig</link>, |
| <link xlink:href="http://docs.oracle.com/javaee/5/api/javax/servlet/ServletContext.html">ServletContext</link>, |
| <link xlink:href="http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpServletRequest.html">HttpServletRequest</link> |
| and |
| <link xlink:href="http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpServletResponse.html">HttpServletResponse</link> |
| are available using &jaxrs.core.Context;. |
| </para> |
| </section> |
| |
| <section> |
| <title>Programmatic resource model</title> |
| |
| <para>Resources can be constructed from classes or instances but also can be constructed from a programmatic resource |
| model. Every resource created from resource classes can also |
| be constructed using the programmatic resource builder api. See <link |
| linkend="resource-builder">resource builder section</link> for more information. |
| </para> |
| </section> |
| |
| </chapter> |