... {noformat} package com.sun.ws.rest.samples.helloworld.resources;
import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path;
// The Java class will be hosted at the URI path "/helloworld" @Path("/helloworld") public class HelloWorldResource {
// The Java method will process HTTP GET requests @GET // The Java method will produce content identified by the MIME Media // type "text/plain" @Produces("text/plain") public String getClichedMessage() { // Return some cliched textual content return "Hello World"; } } {noformat} Let's look at some of the JAX-RS annotations used in this example.
h3. @Path
The [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] annotation's value is a relative URI path. In the example above, the Java class will be hosted at the URI path {{/helloworld}}. This is an extremely simple use of the [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] annotation. What makes JAX-RS so useful is that you can embed variables in the URIs.
_URI path templates_ 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 [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] annotation: {noformat} @Path("/users/{username}") {noformat} 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:
[http://example.com/users/Galileo]
To obtain the value of the username variable the [@PathParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/PathParam.html] may be used on method parameter of a request method, for example: {noformat} @Path("/users/{username}") public class UserResource {
@GET @Produces("text/xml") public String getUser(@PathParam("username") String userName) { ... } } {noformat} 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: {noformat} @Path("users/{username: [a-zA-Z][a-zA-Z_0-9]}") {noformat} 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.
A [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] value may or may not begin with a '/', it makes no difference. Likewise, by default, a [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] 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. However, Jersey has a redirection mechanism, which if enabled, automatically performs redirection to a request URL ending in a '/' if a request URL does not end in a '/' and the matching [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] does end in a '/'.
|
... {noformat} @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; } {noformat} 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). For OPTIONS the the Allow response header will be set to the set of HTTP methods support by the resource. In addition Jersey will return a [WADL|https://wadl.dev.java.net/] document describing the resource.
h3. @Produces
The [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] 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".
[@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] can be applied at both the class and method levels. Here's an example: {noformat} @Path("/myResource") @Produces("text/plain") public class SomeResource { @GET public String doGetAsPlainText() { ... }
@GET @Produces("text/html") public String doGetAsHtml() { ... } } {noformat} The {{doGetAsPlainText}} method defaults to the MIME type of the [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] annotation at the class level. The {{doGetAsHtml}} method's [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] annotation overrides the class-level [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] setting, and specifies that the method can produce HTML rather than plain text.
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 declared what is most acceptable. For example if the Accept header is: {noformat} Accept: text/plain {noformat} then the {{doGetAsPlainText}} method will be invoked. Alternatively if the Accept header is: {noformat} Accept: text/plain;q=0.9, text/html {noformat} which declares that the client can accept media types of "text/plain" and "text/html" but prefers the latter, then the {{doGetAsHtml}} method will be invoked.
More than one media type may be declared in the same [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] declaration, for example: {noformat} @GET @Produces({"application/xml", "application/json"}) public String doGetAsXmlOrJson() { ... } {noformat} The {{doGetAsXmlOrJson}} 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.
The examples above refer 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 [MediaType|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/MediaType.html].
h3. @Consumes
The [@Consumes|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Consumes.html] annotation is used to specify the MIME media types of representations a resource can consume that were sent by the client. The above example can be modified to set the cliched message as follows: {noformat} @POST @Consumes("text/plain") public void postClichedMessage(String message) { // Store the message } {noformat} 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.
[@Consumes|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Consumes.html] can be applied at both the class and method levels and more than one media type may be declared in the same [@Consumes|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Consumes.html] declaration.
h2. Deploying a RESTful Web service
JAX-RS provides the deployment agnostic abstract class [Application|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Application.html] for declaring root resource classes and root resource singleton instances. A Web service may extend this class to declare root resource classes. For example, {noformat} public class MyApplicaton extends Application { public Set<Class<?>> getClasses() { Set<Class<?>> s = new HashSet<Class<?>>(); s.add(HelloWorldResource.class); return s; } } {noformat} Alternatively it is possible to reuse one of Jersey's implementations that scans for root resource classes given a classpath or a set of package names. Such classes are automatically added to the set of classes that are returned by {{getClasses}}. For example, the following scans for root resource classes in packages "org.foo.rest", "org.bar.rest" and in any sub-packages of those two: {noformat} public class MyApplication extends PackagesResourceConfig { public MyApplication() { super("org.foo.rest;org.bar.rest"); } } {noformat} For servlet deployments JAX-RS specifies that a class that implements [Application|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Application.html] may be declared instead of a servlet class in <servlet-class> element of a web.xml, but as of writing this is not currently supported for Jersey. Instead it is necessary to declare the Jersey specific servlet and the [Application|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Application.html] class as follows: {noformat} <web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>MyApplication</param-value> </init-param> </servlet> .... {noformat} Alternatively a simpler approach is to let Jersey choose the PackagesResourceConfig implementation automatically by declaring the packages as follows: {noformat} <web-app> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>org.foo.rest;org.bar.rest</param-value> </init-param> </servlet> .... {noformat} JAX-RS also provides the ability to obtain a container specific artifact from an [Application|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Application.html] instance. For example, Jersey supports using [Grizzly|https://grizzly.dev.java.net/] as follows: {noformat} SelectorThread st = RuntimeDelegate.createEndpoint(new MyApplication(), SelectorThread.class); {noformat} Jersey also provides Grizzly helper classes to deploy the ServletThread instance at a base URL for in-process deployment.
The Jersey samples provide many examples of Servlet-based and Grizzly-in-process-based deployments.
h2. Extracting Request Parameters
Parameters of a resource method may be annotated with parameter-based annotations to extract information from a request. A previous example presented the use [@PathParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/PathParam.html] to extract a path parameter from the path component of the request URL that matched the path declared in [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html].
[@QueryParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/QueryParam.html] is used to extract query parameters from the Query component of the request URL. The following example is an extract from the sparklines sample: {noformat} @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 ) { ... } {noformat} If a query parameter "step" exists in the query component of the request URI then the "step" value will be will 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 [@DefaultValue|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/DefaultValue.html] annotation, will be assigned to the step method parameter. If the "step" value cannot be parsed as an 32 bit signed integer then a 400 (Client Error) response is returned. User defined Java types such as ColorParam may be used, which as implemented as follows: {noformat} 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); } } } } {noformat} In general the Java type of the method parameter may: # Be a primitive type # Have a constructor that accepts a single String argument # Have a static method named valueOf that accepts a single String argument (see, for example, Integer.valueOf(String)) # Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2 or 3 above. The resulting collection is read-only.
Sometimes parameters may contain more than one value for the same name. If this is the case then types in 4) may be used to obtain all values.
If the [@DefaultValue|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/DefaultValue.html] is not used on conjuction with [@QueryParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/QueryParam.html] and the query parameter is not present in the request then value will be an empty collection for List, Set or SortedSet, null for other object types, and the Java-defined default for primitive types.
The @PathParm and the other parameter-based annotations, [@MatrixParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/MatrixParam.html], [@HeaderParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/HeaderParam.html], [@CookieParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/CookieParam.html] and [@FormParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/FormParam.html] obey the same rules as [@QueryParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/QueryParam.html]. [@MatrixParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/MatrixParam.html] extracts information from URL path segments. [@HeaderParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/HeaderParam.html] extracts information from the HTTP headers. [@CookieParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/CookieParam.html] extracts information from the cookies declared in cookie related HTTP headers.
[@FormParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/FormParam.html] is slightly special because it extracts information from a request representation that is of the MIME media type "application/x-www-form-urlencoded" and conforms to the encoding specified by HTML forms, as described [here|http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1]. 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: {noformat} @POST @Consumes("application/x-www-form-urlencoded") public void post(@FormParam("name") String name) { // Store the message } {noformat} 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: {noformat} @GET public String get(@Context UriInfo ui) { MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); MultivaluedMap<String, String> pathParams = ui.getPathParameters(); } {noformat} For header and cookie parameters the following: {noformat} @GET public String get(@Context HttpHeaders hh) { MultivaluedMap<String, String> headerParams = ui.getRequestHeaders(); Map<String, Cookie> pathParams = ui.getCookies(); } {noformat} In general [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html] can be used to obtain contextual Java types related to the request or response.
For form parameters it is possible to do the following: {noformat} @POST @Consumes("application/x-www-form-urlencoded") public void post(MultivaluedMap<String, String> formParams) { // Store the message } {noformat}
h2. Representations and Java types
Previous sections on [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] and [@Consumes|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Consumes.html] referred to MIME media types of representations and showed resource methods that consume and produce the Java type String for a number of different media types. However, String is just one of many Java types that are required to be supported by JAX-RS implementations.
Java types such as byte\[\], java.io.InputStream, java.io.Reader and java.io.File are supported. In addition JAXB beans are supported. Such beans are [JAXBElement|http://java.sun.com/javase/6/docs/api/javax/xml/bind/JAXBElement.html] or classes annotated with [@XmlRootElement|http://java.sun.com/javase/6/docs/api/javax/xml/bind/annotation/XmlRootElement.html] or [@XmlType|http://java.sun.com/javase/6/docs/api/javax/xml/bind/annotation/XmlType.html]. The samples jaxb and json-from-jaxb show the use of JAXB beans.
Unlike method parameters that are associated with the extraction of request parameters, the method parameter associated with the representation being consumed does not require annotating. A maximum of one such unannotated method parameter may exist since there may only be a maximum of one such representation sent in a request.
The representation being produced corresponds to what is returned by the resource method. For example JAX-RS makes it simple to produce images that are instance of File as follows: {noformat} @GET @Path("/images/{image}") @Produces("image/*") public Response getImage(@PathParam("image") String image) { File f = new File(image);
if (!f.exists()) { throw new WebApplicationException(404); }
String mt = new MimetypesFileTypeMap().getContentType(f); return Response.ok(f, mt).build(); } {noformat} A File type can also be used when consuming, a temporary file will be created where the request entity is stored.
The Content-Type (if not set, see next section) can be automatically set from the MIME media types declared by [@Produces|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Produces.html] if the most acceptable media type is not a wild card (one that contains a \*, for example "application/*" or "*/*"). Given the following method: {noformat} @GET @Produces({"application/xml", "application/json"}) public String doGetAsXmlOrJson() { ... } {noformat} if "application/xml" is the most acceptable then the Content-Type of the response will be set to "application/xml".
h2. Building Responses
Sometimes it is necessary to return information additional information in response to a HTTP request. Such information may be built and returned using [Response|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Response.html] and [Response.ResponseBuilder|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Response.ResponseBuilder.html]. For example, a common RESTful pattern for the creation of a new resource is to support a POST request that returns a 201 (Created) status code and a Location header whose value is the URI to the newly created resource. This may be acheived as follows: {noformat} @POST @Consumes("application/xml") public Response post(String content) { URI createdUri = ... create(content); return Response.created(createdUri).build(); } {noformat} In the above no representation produced is returned, this can be achieved by building an entity as part of the response as follows: {noformat} @POST @Consumes("application/xml") public Response post(String content) { URI createdUri = ... String createdContent = create(content); return Response.created(createdUri).entity(createdContent).build(); } {noformat} Response building provides other functionality such as setting the entity tag and last modified date of the representation.
h2. Sub-resources
[@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] may be used on classes and such classes are referred to as root resource classes. [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] 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.
The first way [@Path|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/Path.html] may be used is on resource methods and such methods are referred to as sub-resource methods. The following example shows the method signatures for a root resource class from the jmaki-backend sample: {noformat} @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) { ... } } {noformat} |
... 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) { ... } }
{noformat} The root resource class {{ItemResource}} contains the sub-resource locator method {{getItemContentResource}} 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 {{ItemContentResource}} resource class. Sub-resource locators enable reuse of resource classes.
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).
h2. Building URIs
A very important aspects of REST is hyperlinks, URIs, in representations that clients can use to transition the Web service to new application states (this is otherwise known as "hypermedia as the engine of application state"). HTML forms present a good example of this in practice.
Building URIs and building them safely is not easy with java.net.URI, which is why JAX-RS has the [UriBuilder|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html] class that makes it simple and easy to build URIs safely.
[UriBuilder|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html] can be used to build new URIs or build from existing URIs. For resource classes it is more than likely that URIs will be built from the base URI the Web service is deployed at or from the request URI. The class [UriInfo|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriInfo.html] provides such information (in addition to further information, see next section).
The following example shows URI building with [UriInfo|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriInfo.html] and [UriBuilder|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html] from the bookmark sample: {noformat} @Path("/users/") public class UsersResource {
@Context UriInfo uriInfo;
...
@GET @Produces("application/json") public JSONArray getUsersAsJsonArray() { JSONArray uriArray = new JSONArray(); for (UserEntity userEntity : getUsers()) { UriBuilder ub = uriInfo.getAbsolutePathBuilder(); URI userUri = ub. path(userEntity.getUserid()). build(); uriArray.put(userUri.toASCIIString()); } return uriArray; } } {noformat} [UriInfo|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriInfo.html] is obtained using the [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html] annotation, and in this particular example injection onto the field of the root resource class is performed, previous examples showed the use of [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html] on resource method parameters.
[UriInfo|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriInfo.html] can be used to obtain URIs and associated [UriBuilder|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html] instances for the following URIs: the base URI the application is deployed at; the request URI; and the absolute path URI, which is the request URI minus any query components.
The {{getUsersAsJsonArray}} method constructs a JSONArrray where each element is a URI identifying a specific user resource. The URI is built from the absolute path of the request URI by calling {{uriInfo.getAbsolutePathBuilder()}}. A new path segment is added, which is the user ID, and then the URI is built. Notice that it is not necessary to worry about the inclusion of '/' characters or that the user ID may contain characters that need to be percent encoded. UriBuilder takes care of such details.
[UriBuilder|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html] can be used to build/replace query or matrix parameters. URI templates can also be declared, for example the following will build the URI "http://localhost/segment?name=value": {noformat} UriBuilder.fromUri("http://localhost/"). path("{a}"). queryParam("name", "{value}"). build("segment", "value"); {noformat}
h2. WebApplicationException and mapping Exceptions to Responses
Previous sections have shown how to return HTTP responses and it is possible to return HTTP errors using the same mechanism. However, sometimes when programming in Java it is more natural to use exceptions for HTTP errors.
The following example shows the throwing of a NotFoundException from the bookmark sample: {noformat} @Path("items/{itemid}/") public Item getItem(@PathParam("itemid") String itemid) { Item i = getItems().get(itemid); if (i == null) throw new NotFoundException("Item, " + itemid + ", is not found");
return i; } {noformat} This exception is a Jersey specific exception that extends [WebApplicationException|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/WebApplicationException.html] and builds a HTTP response with the 404 status code and an optional message as the body of the response: {noformat} public class NotFoundException extends WebApplicationException {
/** * Create a HTTP 404 (Not Found) exception. */ public NotFoundException() { super(Responses.notFound().build()); }
/** * Create a HTTP 404 (Not Found) exception. * @param message the String that is the entity of the 404 response. */ public NotFoundException(String message) { super(Response.status(Responses.NOT_FOUND). entity(message).type("text/plain").build()); }
} {noformat} In other cases it may not be appropriate to throw instances of [WebApplicationException|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/WebApplicationException.html], or classes that extend [WebApplicationException|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/WebApplicationException.html], and instead it may be preferable to map an existing exception to a response. For such cases it is possible to use the [ExceptionMapper|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/ext/ExceptionMapper.html] interface. For example, the following maps the [EntityNotFoundException|http://java.sun.com/javaee/5/docs/api/javax/persistence/EntityNotFoundException.html] to a 404 (Not Found) response. {noformat} @Provider public class EntityNotFoundMapper implements ExceptionMapper<javax.persistence.EntityNotFoundException> { public Response toResponse(javax.persistence.EntityNotFoundException ex) { return Response.status(404). entity(ex.getMessage()). type("text/plain"). build(); } } {noformat} The above class is annotated with [@Provider|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/ext/Provider.html], this declares that the class is of interest to the JAX-RS runtime. Such a class may be added to the set of classes of the Application instance that is configured. When an application throws an EntityNotFoundException the toResponse method of the EntityNotFoundMapper instance will be invoked.
h2. Conditional GETs and Returning 304 (Not Modified) Responses
Conditional GETs are a great way to reduce bandwidth, and potentially server-side peformance, depending on how the information used to determine conditions is calculated. A well-designed web site may return 304 (Not Modified) responses for the many of the static images it serves.
JAX-RS provides support for conditional GETs using the contextual interface Request.
The following example shows conditional GET support from the sparklines sample: {noformat} public SparklinesResource( @QueryParam("d") IntegerList data, @DefaultValue("0,100") @QueryParam("limits") Interval limits, @Context Request request, @Context UriInfo ui) { if (data == null) throw new WebApplicationException(400);
this.data = data;
this.limits = limits;
if (!limits.contains(data)) throw new WebApplicationException(400);
this.tag = computeEntityTag(ui.getRequestUri()); if (request.getMethod().equals("GET")) { Response.ResponseBuilder rb = request.evaluatePreconditions(tag); if (rb != null) throw new WebApplicationException(rb.build()); } } {noformat} The constructor of the SparklinesResouce root resource class computes an entity tag from the request URI and then calls the {{[request.evaluatePreconditions|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Request.html#evaluatePreconditions(javax.ws.rs.core.EntityTag)]}} with that entity tag. If a client request contains an "If-None-Match" header with a value that contains the same entity tag that was calculated then the [evaluatePreconditions|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Request.html#evaluatePreconditions(javax.ws.rs.core.EntityTag)] returns a pre-filled out response, with the 304 status code and entity tag set, that may be built and returned. Otherwise, [evaluatePreconditions|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Request.html#evaluatePreconditions(javax.ws.rs.core.EntityTag)] returns null and the normal response can be returned. Notice that in this example the constructor of a resource class can be used perform actions that may otherwise have to be duplicated to invoked for each resource method.
h2. Life-cycle of root resource classes
By default the life-cycle of root resource classes is per-request, 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 SparklinesResource class) without concern for multiple concurrent requests to the same resource.
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.
Instances of singleton root resource classes can be declared by an instance of [Application|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Application.html].
Jersey supports two further life-cycles using Jersey specific annotations. If a root resource class is annotated with @Singleton then only one instance is created per-web applcation. If a root resource class is annotated with @PerSession then one instance is created per web session and stored as a session attribute.
h2. Security
Security information is available by obtaining the [SecurityContext|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/SecurityContext.html] using [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html], which is essentially the equivalent functionality available on the [HttpServletRequest|http://java.sun.com/javaee/5/docs/api/javax/servlet/http/HttpServletRequest.html].
[SecurityContext|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/SecurityContext.html] can be used in conjunction with sub-resource locators to return different resources if the user principle in included in a certain role. For example, a sub-resource locator could return a different resource if a user is a preferred customer: {noformat} @Path("basket") public ShoppingBasketResource get(@Context SecurityContext sc) { if (sc.isUserInRole("PreferredCustomer") { return new PreferredCustomerShoppingBaskestResource(); } else { return new ShoppingBasketResource(); } } {noformat}
h2. Rules of Injection
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. 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: {noformat} @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) { ... } } {noformat} There are some restrictions when injecting on to resource classes with a life-cycle other than per-request. In such cases it is not possible to injected onto fields for the annotations associated with extraction of request parameters. However, it is possible to use the [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html] annotation on fields, in such cases a thread local proxy will be injected.
The [@FormParam|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/FormParam.html] annotation is special and may only be utilized on resource and sub-resource methods. This is because it extracts information from a request entity.
h2. Use of @Context
Previous sections have introduced the use of [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html]. [Chapter 5|https://jsr311.dev.java.net/nonav/releases/1.0/spec/spec3.html#x3-520005] of the JAX-RS specification presents all the standard JAX-RS Java types that may be used with [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html].
When deploying JAX-RS a application using servlet then [ServletConfig|http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletConfig.html], [ServletContext|http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletContext.html], [HttpServletRequest|http://java.sun.com/javaee/5/docs/api/javax/servlet/http/HttpServletRequest.html] and [HttpServletResponse|http://java.sun.com/javaee/5/docs/api/javax/servlet/http/HttpServletResponse.html] are available using [@Context|https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/Context.html].
h2. Annotations Defined By JAX-RS
For a list of the annotations specified by JAX-RS see [Appendix A|https://jsr311.dev.java.net/nonav/releases/1.0/spec/index.html] of the specification. |