JAX-RS : Understanding the Basics

 

What is New in JAX-RS 2.0

Filters

Server

ContainerRequestFilter and ContainerResponseFilter are new server-side request and response filters which can be used to customize various properties of a given request and response.

ContainerRequestFilter annotated with a PreMatching annotation will be run before the runtime has matched a request to a specific JAX-RS root resource and method. Prematching filters can be used to affect the matching process.

The request filters without the PreMatching annotation will run after the JAX-RS resource method has been selected.

ContainerRequestFilter can be used to block a request.

The filters can be bound to individual resource methods only with the help of custom NameBindings.

Multiple request and response filters can be executed in the specific order by using javax.annotation.Priority annotations. See Priorities for more information. Request filters are sorted in the ascending order, response filters - in the descending order.

Client

ClientRequestFilter and ClientResponseFilter are new client-side request and response filters which can be used to customize various properties of a given request and response.

ClientRequestFilter can be used to block a request.

Request filters are sorted in the ascending order, response filters - in the descending order. See Priorities for more information.

Interceptors

ReaderInterceptor and WriterInterceptor can be used in addition to filters or on its own to customize requests and responses on server and client sides.

Interceptors can be useful to customize the reading/writing process and block JAX-RS MessageBodyWriter or MessageBodyReader providers.

The interceptors used on the server side can be bound to individual resource methods only with the help of custom NameBindings.

All interceptors are sorted in the ascending order. See Priorities for more information.

Dynamic Features

Dynamic Feature is a server side feature that can be used to attach request and response filters as well as reader and writer interceptors to specific resource methods. It is an alternative approach to using the NameBindings and offer a finer-grained control over the binding process.

Exceptions

Dedicated exception classes representing various HTTP error or redirect conditions have been introduced, see the 'javax.ws.rs' Package Exceptions section.

For example, instead of throwing a "new WebApplicationException(404)" one is better to do "new NotFoundException()". The finer-grained exception hierarchy allows for a finer-grained support of exception mappers. It also opens a way to check WebApplicationException and all of its subclasses when catching the HTTP exceptions on the client side.

Note that on the client side, ProcessingException can be used to catch client-related exceptions while ResponseProcessingException can be used to narrow down the client side exceptions specifically related to processing the response message.

Suspended invocations

One of the best JAX-RS 2.0 features is the support for server-side asynchronous invocations. Please see the AsyncResponse documentation which provides a very good overview of this feature.

See also this test resource.

Typically, the resource method accepting AsyncResponse will either store it and start a new thread to finish the request, the method will return and the invocation will be suspended, then eventually another thread (either the one which initiated an internal job or some other thread) will resume the suspended call. Note in this case the invocation will be suspended indefinitely until it is resumed.

Another approach is to have AsyncResponse suspended for a limited period of time only and also register a TimeoutHandler. The latter will be invoked when the invocation is resumed by the container after the timeout has expired and the handler will either complete the invocation or suspend it again till it is ready to finish it.

CompletionCallback can be registered with AsyncResponse to receive the notifications when the async response has been sent back.

ConnectionCallback is supported starting from CXF 3.0.0-milestone2.

This feature can help developers write very sophisticated asynchronous applications.

Please also see the page about CXF Continuations API which JAX-RS 2.0 AsyncResponse implementation is based upon and
how to configure CXFServlet.

Parameter converters

ParamConverterProvider can be used to manage the conversion of custom Objects to String and vice versa on the server and client sides, when processing JAX-RS parameters representing URI parts or headers or form elements and when a default conversion mechanism does not work. For example, java.util.Date constructor accepting a String may have to be replaced a custom ParamConverter.

Bean parameters

BeanParam can be used to get JAX-RS parameters representing URI parts or headers or form elements and also contexts injected into a single bean container.

Note the CXF extension supporting the injection of all the parameters of specific JAX-RS type (example, QueryParam("") MyBean) is different, it only allows to get all the query parameters injected, but it also does not require that bean properties are annotated with QueryParam/etc annotations.

ResourceInfo

ResourceInfo is a new JAX-RS context which can be injected into filters and interceptors and checked which resource class and method are about to be invoked.

Injection into subresources

Subresources can get JAX-RS contexts injected directly into their fields with the help of ResourceContext.

When possible, having a parent resource injecting the contexts into a given subresource instance via a setter or constructor can offer a much simpler alternative.

Updates to the matching algorithm

JAX-RS 2.0 supports a proper resource method selection in cases where multiple root resource classes have the same Path value, for example:

In JAX-RS 1.1 a request with URI such as "/1" is not guaranteed to be matched and in CXF 2.7.x or earlier the use of CXF specific ResourceComparator is required to ensure Root1 and its get() method gets selected. In CXF 3.0.0 Root1 get() will always be correctly selected. Note ResourceComparator may still be of help in some cases even in CXF 3.0.0.

Link is a utility class for building HTTP links as HTTP Link headers or application data links.
UriInfo, UriBuilder, Response and ResponseBuilder classes have been enhanced to support Link.

Client API

JAX-RS 2.0 Client API has been completely implemented in CXF 3.0.0, please see the Client API page for more information.

Resource class

A resource class is a Java class annotated with JAX-RS annotations to represent a Web resource. Two types of resource classes are available: root resource classes and subresource classes. A root resource class is annotated with at least a @Path annotation, while subresource classes typically have no root @Path values. A typical root resource class in JAX-RS looks like this below:

Customer resource class can handle requests starting from /customerservice. When /customerservice requests are matched to this class, its getCustomers() method will be selected. updateCustomer(), deleteCustomer() and addCustomer() are used to serve POST, PUT and DELETE requests starting from /customerservice/customer, while getOrder() method delegates the handling of requests like /customerservice/orders/1 to a subresource locator Order.

The @Produces annotation is used to specify the format of the response. When not available on the resource method, it's inherited from a class, and if it's not available on the class then it's inherited from a corresponding message body writer, if any. Default value is */*, but it's recommended that some definite value is specified. The same applies to @Consumes, except that it's the message body readers that are checked as the last resort.

For example, getCustomers() method inherits @Produces annotation from its class, while getCustomer() method overrides it with its own value.

@Path

The @Path annotation is applied to resource classes or methods. The value of @Path annotation is a relative URI path and follows the URI Template format and may include arbitrary regular expressions. When not available on the resource method, it's inherited from a class. For example:

This example is similar to the one above it, but it also shows that an {id} template variable specified as part of the root @Path expression is reused by resource methods and a custom regular expression is specified by a findItem() method (note that a variable name is separated by ':' from an actual expression).

In this example, a request like 'GET /customers/1/order/2/price/2000/weight/2' will be served by the findItem() method.
List<PathSegment> can be used to get to all the path segments in 'price/2000/weight/2' captured by the regular expression.

More information about Path annotations can be found from JAX-RS spec section 2.3.

HTTP Method

The JAX-RS specification defines a number of annotations such as @GET, @PUT, @POST and @DELETE. Using an @HttpMethod designator, one can create a custom annotation such as @Update or @Patch. For example :

Return types

Either javax.ws.rs.core.Response or custom type can be returned. javax.ws.rs.core.Response can be used to set the HTTP response code, headers and entity. JAX-RS MessageBodyWriters (see below) are in charge of serializing the response entities, those which are returned directly or as part of javax.ws.rs.core.Response.

Response Streaming 

JAX-RS StreamingOutput

StreamingOutput can be used to stream the data to the client, for example:

CXF StreamingResponse

CXF 3.0.0 introduces StreamingResponse extension. It can be used with the WebSocket transport or as a possible replacement for the code working with StreamingOutput.

For example, consider that a number of resources need to be returned as they become available:

Exception handling

One can either throw an unchecked WebApplicationException or return Response with a proper error code set.
The former option may be a better one when no JAX-RS types can be added to method signatures.

For example :

Yet another option is to register an ExceptionMapper provider. Ex :

This allows for throwing a checked or runtime exception from an application code and map it to an HTTP response in a registered provider.

Have a look please at this exception mapper which converts Spring Security exceptions into HTTP 403 error code for another example.

Note that when no mappers are found for custom exceptions, they are propagated to the underlying container as required by the specification where they will typically be wrapped in ServlerException, eventually resulting in HTTP 500 status being returned by default. Thus one option for intercepting the exceptions is to register a custom servlet filter which will catch ServletExceptions and handle the causes.

This propagation can be disabled by registering a boolean jaxrs property 'org.apache.cxf.propagate.exception' with a false value. If such property is set and no exception mapper can be found for a given exception then it will be wrapped into an xml error response by the CXF XMLFaultOutInterceptor.

One can also register a custom CXF out fault interceptor which can handle all the exceptions by writing directly to the HttpServletResponse stream or XMLStreamWriter (as XMLFaultOutInterceptor does). For example, see this test interceptor.

Mapping exceptions thrown from CXF interceptors

Starting from CXF 2.7.8 it is also possible to use registered ExceptionMappers to map the exceptions thrown from CXF server in interceptors which are registered after JAXRSInInterceptor (Phase.UNMARSHAL) and out interceptors registered before JAXRSOutInterceptor (Phase.MARSHAL).
In earlier CXF versions such exceptions are only possible to handle with CXF fault in interceptors.

In order to get the exceptions thrown from CXF in interceptors mapped, set a "map.cxf.interceptor.fault" contextual property to true - needed in CXF 2.7.8 to ensure existing in fault interceptors are not affected; the mapping is done by default starting from CXF 3.0.0.

In order to get the exceptions thrown from CXF out interceptors mapped, add org.apache.cxf.jaxrs.interceptor.JAXRSOutExceptionMapperInterceptor to the list of out interceptors.

Customizing default WebApplicationException mapper

CXF ships a WebApplicationException mapper, org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper. By default it logs a stack trace at a warning level and returns Response available in the captured exception.
It can be configured to log a stack trace at a trace level, by setting a 'printStackTrace' property to 'false'. Alternatively, if org.apache.cxf.logging.FaultListener is registered (as a contextual property) and indicates that it handled a given exception, then no more logging is done.

A simple text error message can also be optionally reported, by setting an 'addMessageToResponse' property to 'true'.
Note that the custom WebApplicationException mapper, if registered, will be preferred to the default one.

Dealing with Parameters

PathParam annotation is used to map a given Path template variable to a method parameter.
For example :

In this case a template variable id available from a root class annotation is mapped to a parameter of type Long, while a name variable is mapped to a parameter of type String.

@QueryParam, @HttpHeader, @MatrixParam, @FormParam and @CookieParam annotations are also supported.
Parameters can be of type String or of any type that have constructors accepting a String parameter or static valueOf(String s) methods.
Additionally CXF JAXRS checks for static fromString(String s) method, so types with no valueOf(String) factory methods can also be dealt with:

Note that on the trunk enums with fromValue() factory methods are also supported.

JAX-RS PathSegment is also supported. A sequence of identically named parameters (queries, headers, etc) can be mapped to List or Set or SortedSet.

CXF JAXRS supports ParameterHandler extensions which can be used to deal with method parameters annotated with one of the JAXRS parameter annotations :

Note that ParameterHandlers can not be used to deal with parameters representing a message body, "byte[] byte" in this example. MessageBodyReaders have to deal with this task. That said, a given MessageBodyReader implementation can also implement ParameterHandler.

ParameterHandlers can be registered as providers either from Spring or programmatically.
Note that by default the handlers are checked last after all the other options recommended by the JAX-RS specification have been tried.
Starting from CXF 2.5.3 the handlers will always be checked first for java.util.Date and java.util.Locale parameters. Additionally, a "check.parameter.handlers.first" contextual property can be used to get the handlers checked first when the parameters of other types are processed.

All the parameters are automatically decoded. This can be disabled by using @Encoded annotation.
Parameters can have a default value set using a DefaultValue annotation :

JAX-RS mandates that only a single method parameter which is not annotated with JAXRS annotations applicable to method parameters is allowed in a resource method. For example :

Parameters like 'String body' are expected to represent the request body/input stream. It's the job of JAX-RS MessageBodyReaders to deserialize the request body into an object of the expected type.

It's also possible to inject all types of parameters into fields or through dedicated setters. For example, the first code fragment in this section can be rewritten like this:

Parameter beans

There's a CXF extension which makes it possible to inject a sequence of @PathParam, @QueryParam, @FormParam or @MatrixParam parameters into a bean. For example:

Note that there's a single @PathParam with an empty value in updateCustomer() - this is an extension bit. The value for a template variable 'id' is injected into Customer.setId(Long id), while the value for 'name' is injected into Customer.setName(String s). The setter methods should have a single parameter, the conversion from the actual value to the parameter instance follows the same procedure as outlined above.

Similarly, in getCustomerOrder(), OrderBean can be injected with corresponding values from a query string like ?id=1&weight=2 or from matrix parameters set as part of one of the path segments : /customer/1/order;id=1;weight=2. Likewise, in addCustomerOrder(), FormParam("") can capture all the values submitted from an HTML form and inject them into OrderBean.

Nested beans are also supported, which among other things, makes it possible to formulate advanced search queries. For example, given the following bean definitions:

a query like

> /getPerson?sex=M&legalName.first=John&legalName.last=Doe&homeAddr.city=Reno&homeAddr.state=NV

will result in a Person bean being properly initialized and all the search criteria being captured and easily accessible. Note more enhancements are being planned in this area.

Resource lifecycles

The scopes which are supported by default are Singleton and Prototype(per-request).
Note that JAXRS MessageBodyWriter and MessageBodyReader providers are always singletons.

Classes with prototype scopes can get JAXRS contexts or parameters injected at construction time:

Classes with singleton scopes can only have contexts injected at the construction time and it is only a CXFNonSpringJaxrsServlet which can do it. In most cases you can have contexts injected as bean properties right after construction time.

See the "Lifecycle management" section for more details.

Overview of the selection algorithm.

The JAX-RS Selection algorithm is used to select root resource classes, resource methods and subresource locators.

Selecting between multiple resource classes

When multiple resource classes match a given URI request, the following algorithm is used :
1. Prefer the resource class which has more literal characters in its @Path annotation.

Both classes match /bar/1/baz requests but Test2 will be selected as it has 9 Path literal characters compared to 5 in Test1. Similarly, Test4 wins against Test3 when a /foo/ request arrives.

2. Prefer the resource class which has more capturing groups in its @Path annotation.

Both classes match /bar/1/2 requests and both have the same number of literal characters but Test2 will be selected as it has 2 Path capturing groups (id and id1) as opposed to 1 in Test1.

3. Prefer the resource class which has more capturing groups with arbitrary regular expressions in its @Path annotation.

Both classes match /bar/1/baz/2 requests and both have the same number of literal characters and capturing groups but Test1 will be selected as it has 1 Path capturing groups with the arbitrary regular expression (id) as opposed to 0 in Test2.

Selecting between multiple resource methods

Once the resource class has been selected, the next step is to choose a resource method. If multiple methods can be matched then the same rules which are used for selecting resource classes are applied. Additionally, one more rule is used.

4. Prefer a resource method to a subresource locator method

Both getOrderFromSubresource() and getOrder() methods can be used to serve a /bar request. However, getOrder() wins.

Resource methods and media types

Consider this resource class with 2 resource methods :

Both methods match /bar requests. If in a given request both Content-Type and Accept are set to application/xml then getOrderXML will be selected. If both Content-Type and Accept are set to application/json then getOrderJSON will be chosen instead.

For this specific example, in both cases either JAXB or JSON message body readers and writers will be selected to deserialize the input stream into OrderDetails and serialize Order into the output stream. Message body providers can have @Produces and @Consumes set too, and they have to match those on a chosen resource method.

The above code can be replaced with this one :

Custom selection between multiple resources

The JAX-RS selection algorithm has been designed with a lot of attention being paid to various possible cases, as far as the selection between multiple matching resource classes or methods is concerned.

However, in some cases, users have reported the algorithm being somewhat restrictive in the way multiple resource classes are selected. For example, by default, after a given resource class has been matched and if this class has no matching resource method, then the algorithm stops executing, without attempting to check the remaining matching resource classes.

Starting from CXF 2.2.5 it is possible to register a custom ResourceComparator implementation using a jaxrs:server/jaxrs:resourceComparator element, example:

Custom implementations can check the names of the resource classes or methods being compared and given the current request URI they can make sure that the required class or method is chosen by returning either -1 or 1, as needed. If 0 is returned then the runtime will proceed with executing the default selection algorithm. At the moment the easiest way to get to the details such as the current request URI is to create an instance of the CXF JAXRS UriInfoImpl using a constructor accepting a Message.

Note that by the time a custom ResourceComparator is called the provided resource classes or methods have already been successfully matched by the runtime.

For example, the optional HTTP request and URI parameters (query, matrix, headers, cookies) and form parameters do not affect the selection algorithm.
A custom ResourceComparator can be used when this limitation is considered to be problematic. For example, the following shows one such implementation:

Now consider this code:

Using the custom comparator will lead to getFoo() method accepting a single query parameter selected when a request URI has only one query parameter, and getFoo() method accepting multiple query parameters selected when a request URI has at least two query parameters. Further customizations may also be possible.

Context annotations

A number of context types can be injected as parameters, in fields or through dedicated methods.
UriInfo, SecurityContext, HttpHeaders, Providers, Request, ContextResolver, Servlet types (HttpServletRequest, HttpServletResponse, ServletContext, ServletConfig) can be injected.

A CXF-specific composite context interface, MessageContext is also supported which makes it easier to deal with all the supported JAX-RS contexts (and indeed with future ones) and also lets us check the current message's properties.

Example:

Note that all types of supported JAX-RS providers such as MessageBodyWriter, MessageBodyReader, ExceptionMapper and ContextResolver, as well as the list of body providers which can be provided by Providers can have contexts injected too. The only exception is that no parameter level injection is supported for providers due to methods of JAXRS providers being fixed.

Note that Providers and ContextResolver are likely to be of interest to message body providers rather than to the actual application code. You can also inject all the context types into @Resource annotated fields.

Custom Contexts

Registering a custom ContextProvider implementation such as SearchContextProvider lets attach Context annotations to arbitrary classes which can be helpful when some of the information representing the current request needs to be optimized or specialized, example:

and

Custom Context implementations may get all the information about the HTTP request from the current CXF message.

URI calculation using UriInfo and UriBuilder

Mapping of a particular URI to a service that returns some resource is straightforward using the @Path annotation. However RESTful services are often connected: one service returns data that is used as the key in another service. Listing entities and accessing a particular entity is a typical example:

For this service we can assume that the returned list of customers exposes only basic attributes and more details is returned using the second method which uses the customer id as the key. Something like this:

How does a client of this service know how to get from list of customers to given customer? A trivial approach would be to expect the client to compute the proper URI. But wouldn't it be better to have the services provide full URIs in the response that can be used directly? This way the client would be more decoupled from the service itself (which may change URI format over time). A client could be provided the following on response, for example:

The problem for the service is how to determine these URIs when the paths come from @Path annotations. It gets more complicated as we consider paths with templates (variables) on multiple levels or sub-resources introducing dynamic routing to different URIs.

The core part of the solution is to inject the UriInfo object into method "getCustomers". This helper object allows for extracting useful information about the current URI context, but more importantly allows for getting the UriBuilder object. UriBuilder has multiple appender methods for building the URI for each object; in our case to the stem URI we can append path in multiple ways, providing it as a string (which we actually want to avoid here) or a resource (class or method) to extract the @Path value. Finally UriBuilder must have values bound to its template variables to render the actual URI. This case in action looks like this:

Annotation inheritance

Most of the JAX-RS annotations can be inherited from either an interface or a superclass. For example:

Similarly, annotations can be inherited from super-classes. In CXF, the resource class will inherit the class-level annotations from both its implemented interfaces and any class it extends.

Sub-resource locators.

A method of a resource class that is annotated with @Path becomes a sub-resource locator when no annotation with an HttpMethod designator like @GET is present. Sub-resource locators are used to further resolve the object that will handle the request. They can delegate to other sub-resource locators, including themselves.

In the example below, getOrder method is a sub-resource locator:

A HTTP GET request to http://localhost:9000/customerservice/orders/223/products/323 is dispatched to getOrder method first. If the Order resource whose id is 223 is found, the Order 223 will be used to further resolve Product resource. Eventually, a Product 323 that belongs to Order 223 will be returned. Similarly, the request to http://localhost:9000/customerservice/orders/223/products/323/items will be delivered to the getItems(productId) method.

Note that a subresource class like Order often has no root @Path annotations which means that they're delegated to dynamically at runtime, in other words, they can not be invoked upon before one of the root resource classes is invoked first. A root resource class (which has a root @\Path annotation) can become a subresource too if one of its subresource locator methods delegates to it, similar to Order.getItems(productId) above.

Note that a given subresource can be represented as an interface or some base class resolved to an actual class at runtime. In this case any resource methods which have to be invoked on an actual subresource instance are discovered dynamically at runtime:

Static resolution of subresources

By default, subresources are resolved dynamically at runtime. This is a slower procedure, partly due to the fact that a concrete subresource implementation may introduce some JAXRS annotations in addition to those which might be available at the interface typed by a subresource locator method and different to those available on another subresource instance implementing the same interface.

If you know that all the JAXRS annotations are available on a given subresource type (or one of its superclasses or interfaces) returned by a subresource locator method then you may want to disable the dynamic resolution :

Note - starting from CXF 2.7.2 the injection of JAX-RS contexts and parameters will also be supported if this property has been enabled.

Message Body Providers

JAX-RS relies on MessageBodyReader and MessageBodyWriter implementations to serialize and de-serialize Java types. JAX-RS requires that certain types has to be supported out of the box.
By default, CXF supports String, byte[], InputStream, Reader, File, JAXP Source, JAX-RS StreamingOutput, JAXB-annotated types with application/xml, text/xml and application/json formats as well as JAXBElement (see below). JAX-RS MultivaluedMap is also supported for form contents.

See also the "Support for data bindings" section below.

Custom Message Body Providers

It's likely that a given application may need to deal with types that are not supported by default. Alternatively, developers may want to provide a more efficient implementation for handling default types such as InputStream.

Here's an example of a custom MessageBodyReader for InputStream:

and here's an example of a custom MessageBodyWriter for Long objects:

CXF ships some custom providers too, for dealing with Atom (based on Apache Abdera) and XMLObjects. CXF also supports primitive types and their Number friends when text/plain media type is used, either on input or output.

Registering custom providers

Putting @Provider annotation on the provider class is something that should lead to your provider being registered with the runtime. CXF does not support this feature yet.

One can easily register a provider either from Spring configuration or programmatically:

Note that instead of the older <jaxrs:entityProviders> it's now <jaxrs:providers>. JAX-RS supports different types of providers and having a single <jaxrs:providers> container is in line with the way other JAX-RS implementations discover providers by checking for @Provider annotations only.

See below for a more complete beans.xml definition.

While having @Provider-annotated providers automatically registered is a handy feature indeed, sometimes it might actually be problematic. For example, in a large project user providers from different libraries might clash.

When using the custom configuration (as shown above) provider instances of different types (handling the same format of request/response bodies) or differently configured instances of the same type can be registered with a different jaxrs:server instance. Yet another requirement might be to have only a given jaxrs:server endpoint among multiple available ones to handle requests with a given media type:

In this example a single service bean can be accessed through 3 different paths, /1, /2 and /3. InputStream provider is available on all the 3 paths. com.bar.providers.InputStreamProvider is used in 2 cases, while a special InputStream handler baz.foo.jaxrsproviders.InputStreamProvider from another library is also involved in one case.

Customizing media types for message body providers

As explained above, message body providers can play a major part in affecting the way target resource methods are matched. If a method returns a custom type Foo and a MessageBodyWriter<Foo> is available then it will be used only if one of the media types specified in a given request's HTTP Accept header matches or intersects with one of the media types specified by @Produces annotation in a MessageBodyWriter<Foo> implementation. The same applies if a method accepts a custom type Foo, but this time the value of @Consumes in MessageBodyReader<Foo> will be matched against a request's ContentType value.

Sometimes users would like to experiment with media types different to those statically supported by a given message body reader/writer. For example, application/xml might seem a bit too general in some cases and people may want to try some custom/xml type and still use a default JAXB provider.

In such cases it's possible to override the default @Produces and/or @Consumes types supported by a given provider. It only currently works for JAXBElementProvider and JSONProvider, but any custom provider can avail of this support by simply having setter/getter pairs for either produce and/or consume types and the JAXRS runtime will use them instead.
See this example on how to provide custom media types from Spring.

Advanced HTTP

The JAX-RS specification requires support for a number of advanced HTTP features.

JAX-RS Request context object can be used to check the preconditions expressed via headers such as If-Match, If-None-Match, If-Modified-Since and If-Unmodified-Since.

JAX-RS also makes it easier to work with ETag, Vary, CacheControl, Cookie and Set-Cookie headers.