| <?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="https://jakarta.ee/specifications/restful-ws/3.0/jakarta-restful-ws-spec-3.0.pdf">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="https://repo1.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 jakarta.ws.rs.GET; |
| import jakarta.ws.rs.Path; |
| import jakarta.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="https://javaee.github.io/wadl/">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>jakarta.ws.rs.ext.ParamConverterProvider</literal> JAX-RS |
| extension SPI that returns a <literal>jakarta.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 jakarta.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>jakarta.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>jakarta.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="https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/ServletConfig.html">ServletConfig</link>, |
| <link xlink:href="https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/ServletContext.html">ServletContext</link>, |
| <link xlink:href="https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/http/HttpServletRequest.html">HttpServletRequest</link> |
| and |
| <link xlink:href="https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/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> |