| <?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> | |
| For quicker getting of values for a known header name there is a shortcut for <literal>hh.getRequestHeaders().get(name)</literal> | |
| which is <literal>hh.getRequestHeader(name)</literal>. | |
| </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> |