Ce contenu n'est pas disponible dans la langue sélectionnée.
Chapter 61. JAX-RS 2.0 Filters and Interceptors
Abstract
JAX-RS 2.0 defines standard APIs and semantics for installing filters and interceptors in the processing pipeline for REST invocations. Filters and interceptors are typically used to provide such capabilities as logging, authentication, authorization, message compression, message encryption, and so on.
61.1. Introduction to JAX-RS Filters and Interceptors Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section provides an overview of the processing pipeline for JAX-RS filters and interceptors, highlighting the extension points where it is possible to install a filter chain or an interceptor chain.
Filters Copier lienLien copié sur presse-papiers!
A JAX-RS 2.0 filter is a type of plug-in that gives a developer access to all of the JAX-RS messages passing through a CXF client or server. A filter is suitable for processing the metadata associated with a message: HTTP headers, query parameters, media type, and other metadata. Filters have the capability to abort a message invocation (useful for security plug-ins, for example).
If you like, you can install multiple filters at each extension point, in which case the filters are executed in a chain (the order of execution is undefined, however, unless you specify a priority value for each installed filter).
Interceptors Copier lienLien copié sur presse-papiers!
A JAX-RS 2.0 interceptor is a type of plug-in that gives a developer access to a message body as it is being read or written. Interceptors are wrapped around either the MessageBodyReader.readFrom
method invocation (for reader interceptors) or the MessageBodyWriter.writeTo
method invocation (for writer interceptors).
If you like, you can install multiple interceptors at each extension point, in which case the interceptors are executed in a chain (the order of execution is undefined, however, unless you specify a priority value for each installed interceptor).
Server processing pipeline Copier lienLien copié sur presse-papiers!
Figure 61.1, “Server-Side Filter and Interceptor Extension Points” shows an outline of the processing pipeline for JAX-RS filters and interceptors installed on the server side.
Figure 61.1. Server-Side Filter and Interceptor Extension Points
Server extension points Copier lienLien copié sur presse-papiers!
In the server processing pipeline, you can add a filter (or interceptor) at any of the following extension points:
-
PreMatchContainerRequest
filter -
ContainerRequest
filter -
ReadInterceptor
-
ContainerResponse
filter -
WriteInterceptor
Note that the PreMatchContainerRequest
extension point is reached before resource matching has occurred, so some of the context metadata will not be available at this point.
Client processing pipeline Copier lienLien copié sur presse-papiers!
Figure 61.2, “Client-Side Filter and Interceptor Extension Points” shows an outline of the processing pipeline for JAX-RS filters and interceptors installed on the client side.
Figure 61.2. Client-Side Filter and Interceptor Extension Points
Client extension points Copier lienLien copié sur presse-papiers!
In the client processing pipeline, you can add a filter (or interceptor) at any of the following extension points:
-
ClientRequest
filter -
WriteInterceptor
-
ClientResponse
filter -
ReadInterceptor
Filter and interceptor order Copier lienLien copié sur presse-papiers!
If you install multiple filters or interceptors at the same extension point, the execution order of the filters depends on the priority assigned to them (using the @Priority
annotation in the Java source). A priority is represented as an integer value. In general, a filter with a higher priority number is placed closer to the resource method invocation on the server side; while a filter with a lower priority number is placed closer to the client invocation. In other words, the filters and interceptors acting on a request message are executed in ascending order of priority number; while the filters and interceptors acting on a response message are executed in descending order of priority number.
Filter classes Copier lienLien copié sur presse-papiers!
The following Java interfaces can be implemented in order to create custom REST message filters:
Interceptor classes Copier lienLien copié sur presse-papiers!
The following Java interfaces can be implemented in order to create custom REST message interceptors:
61.2. Container Request Filter Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section explains how to implement and register a container request filter, which is used to intercept an incoming request message on the server (container) side. Container request filters are often used to process headers on the server side and can be used for any kind of generic request processing (that is, processing that is independent of the particular resource method called).
Moreover, the container request filter is something of a special case, because it can be installed at two distinct extension points: PreMatchContainerRequest
(before the resource matching step); and ContainerRequest
(after the resource matching step).
ContainerRequestFilter interface Copier lienLien copié sur presse-papiers!
The javax.ws.rs.container.ContainerRequestFilter
interface is defined as follows:
By implementing the ContainerRequestFilter
interface, you can create a filter for either of the following extension points on the server side:
-
PreMatchContainerRequest
-
ContainerRequest
ContainerRequestContext interface Copier lienLien copié sur presse-papiers!
The filter
method of ContainerRequestFilter
receives a single argument of type javax.ws.rs.container.ContainerRequestContext
, which can be used to access the incoming request message and its related metadata. The ContainerRequestContext
interface is defined as follows:
Sample implementation for PreMatchContainerRequest filter Copier lienLien copié sur presse-papiers!
To implement a container request filter for the PreMatchContainerRequest
extension point (that is, where the filter is executed prior to resource matching), define a class that implements the ContainerRequestFilter
interface, making sure to annotate the class with the @PreMatching
annotation (to select the PreMatchContainerRequest
extension point).
For example, the following code shows an example of a simple container request filter that gets installed in the PreMatchContainerRequest
extension point, with a priority of 20:
Sample implementation for ContainerRequest filter Copier lienLien copié sur presse-papiers!
To implement a container request filter for the ContainerRequest
extension point (that is, where the filter is executed after resource matching), define a class that implements the ContainerRequestFilter
interface, without the @PreMatching
annotation.
For example, the following code shows an example of a simple container request filter that gets installed in the ContainerRequest
extension point, with a priority of 30:
Injecting ResourceInfo Copier lienLien copié sur presse-papiers!
At the ContainerRequest
extension point (that is, after resource matching has occurred), it is possible to access the matched resource class and resource method by injecting the ResourceInfo
class. For example, the following code shows how to inject the ResourceInfo
class as a field of the ContainerRequestFilter
class:
Aborting the invocation Copier lienLien copié sur presse-papiers!
It is possible to abort a server-side invocation by creating a suitable implementation of a container request filter. Typically, this is useful for implementing security features on the server side: for example, to implement an authentication feature or an authorization feature. If an incoming request fails to authenticate successfully, you could abort the invocation from within the container request filter.
For example, the following pre-matching feature attempts to extract a username and password from the URI’s query parameters and calls an authenticate method to check the username and password credentials. If the authentication fails, the invocation is aborted by calling abortWith
on the ContainerRequestContext
object, passing the error response that is to be returned to the client.
Binding the server request filter Copier lienLien copié sur presse-papiers!
To bind a server request filter (that is, to install it into the Apache CXF runtime), perform the following steps:
Add the
@Provider
annotation to the container request filter class, as shown in the following code fragment:Copy to Clipboard Copied! Toggle word wrap Toggle overflow When the container request filter implementation is loaded into the Apache CXF runtime, the REST implementation automatically scans the loaded classes to search for the classes marked with the
@Provider
annotation (the scanning phase).When defining a JAX-RS server endpoint in XML (for example, see Section 18.1, “Configuring JAX-RS Server Endpoints”), add the server request filter to the list of providers in the
jaxrs:providers
element.Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteThis step is a non-standard requirement of Apache CXF. Strictly speaking, according to the JAX-RS standard, the
@Provider
annotation should be all that is required to bind the filter. But in practice, the standard approach is somewhat inflexible and can lead to clashing providers when many libraries are included in a large project.
61.3. Container Response Filter Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section explains how to implement and register a container response filter, which is used to intercept an outgoing response message on the server side. Container response filters can be used to populate headers automatically in a response message and, in general, can be used for any kind of generic response processing.
ContainerResponseFilter interface Copier lienLien copié sur presse-papiers!
The javax.ws.rs.container.ContainerResponseFilter
interface is defined as follows:
By implementing the ContainerResponseFilter
, you can create a filter for the ContainerResponse
extension point on the server side, which filters the response message after the invocation has executed.
The container response filter gives you access both to the request message (through the requestContext
argument) and the response message (through the responseContext
message), but only the response can be modified at this stage.
ContainerResponseContext interface Copier lienLien copié sur presse-papiers!
The filter
method of ContainerResponseFilter
receives two arguments: an argument of type javax.ws.rs.container.ContainerRequestContext
(see the section called “ContainerRequestContext interface”); and an argument of type javax.ws.rs.container.ContainerResponseContext
, which can be used to access the outgoing response message and its related metadata.
The ContainerResponseContext
interface is defined as follows:
Sample implementation Copier lienLien copié sur presse-papiers!
To implement a container response filter for the ContainerResponse
extension point (that is, where the filter is executed after the invocation has been executed on the server side), define a class that implements the ContainerResponseFilter
interface.
For example, the following code shows an example of a simple container response filter that gets installed in the ContainerResponse
extension point, with a priority of 10:
Binding the server response filter Copier lienLien copié sur presse-papiers!
To bind a server response filter (that is, to install it into the Apache CXF runtime), perform the following steps:
Add the
@Provider
annotation to the container response filter class, as shown in the following code fragment:Copy to Clipboard Copied! Toggle word wrap Toggle overflow When the container response filter implementation is loaded into the Apache CXF runtime, the REST implementation automatically scans the loaded classes to search for the classes marked with the
@Provider
annotation (the scanning phase).When defining a JAX-RS server endpoint in XML (for example, see Section 18.1, “Configuring JAX-RS Server Endpoints”), add the server response filter to the list of providers in the
jaxrs:providers
element.Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteThis step is a non-standard requirement of Apache CXF. Strictly speaking, according to the JAX-RS standard, the
@Provider
annotation should be all that is required to bind the filter. But in practice, the standard approach is somewhat inflexible and can lead to clashing providers when many libraries are included in a large project.
61.4. Client Request Filter Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section explains how to implement and register a client request filter, which is used to intercept an outgoing request message on the client side. Client request filters are often used to process headers and can be used for any kind of generic request processing.
ClientRequestFilter interface Copier lienLien copié sur presse-papiers!
The javax.ws.rs.client.ClientRequestFilter
interface is defined as follows:
By implementing the ClientRequestFilter
, you can create a filter for the ClientRequest
extension point on the client side, which filters the request message before sending the message to the server.
ClientRequestContext interface Copier lienLien copié sur presse-papiers!
The filter
method of ClientRequestFilter
receives a single argument of type javax.ws.rs.client.ClientRequestContext
, which can be used to access the outgoing request message and its related metadata. The ClientRequestContext
interface is defined as follows:
Sample implementation Copier lienLien copié sur presse-papiers!
To implement a client request filter for the ClientRequest
extension point (that is, where the filter is executed prior to sending the request message), define a class that implements the ClientRequestFilter
interface.
For example, the following code shows an example of a simple client request filter that gets installed in the ClientRequest
extension point, with a priority of 20:
Aborting the invocation Copier lienLien copié sur presse-papiers!
It is possible to abort a client-side invocation by implementing a suitable client request filter. For example, you might implement a client-side filter to check whether a request is correctly formatted and, if necessary, abort the request.
The following test code always aborts the request, returning the BAD_REQUEST
HTTP status to the client calling code:
Registering the client request filter Copier lienLien copié sur presse-papiers!
Using the JAX-RS 2.0 client API, you can register a client request filter directly on a javax.ws.rs.client.Client
object or on a javax.ws.rs.client.WebTarget
object. Effectively, this means that the client request filter can optionally be applied to different scopes, so that only certain URI paths are affected by the filter.
For example, the following code shows how to register the SampleClientRequestFilter
filter so that it applies to all invocations made using the client
object; and how to register the TestAbortClientRequestFilter
filter, so that it applies only to sub-paths of rest/TestAbortClientRequest
.
61.5. Client Response Filter Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section explains how to implement and register a client response filter, which is used to intercept an incoming response message on the client side. Client response filters can be used for any kind of generic response processing on the client side.
ClientResponseFilter interface Copier lienLien copié sur presse-papiers!
The javax.ws.rs.client.ClientResponseFilter
interface is defined as follows:
By implementing the ClientResponseFilter
, you can create a filter for the ClientResponse
extension point on the client side, which filters the response message after it is received from the server.
ClientResponseContext interface Copier lienLien copié sur presse-papiers!
The filter
method of ClientResponseFilter
receives two arguments: an argument of type javax.ws.rs.client.ClientRequestContext
(see the section called “ClientRequestContext interface”); and an argument of type javax.ws.rs.client.ClientResponseContext
, which can be used to access the outgoing response message and its related metadata.
The ClientResponseContext
interface is defined as follows:
Sample implementation Copier lienLien copié sur presse-papiers!
To implement a client response filter for the ClientResponse
extension point (that is, where the filter is executed after receiving a response message from the server), define a class that implements the ClientResponseFilter
interface.
For example, the following code shows an example of a simple client response filter that gets installed in the ClientResponse
extension point, with a priority of 20:
Registering the client response filter Copier lienLien copié sur presse-papiers!
Using the JAX-RS 2.0 client API, you can register a client response filter directly on a javax.ws.rs.client.Client
object or on a javax.ws.rs.client.WebTarget
object. Effectively, this means that the client request filter can optionally be applied to different scopes, so that only certain URI paths are affected by the filter.
For example, the following code shows how to register the SampleClientResponseFilter
filter so that it applies to all invocations made using the client
object:
61.6. Entity Reader Interceptor Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section explains how to implement and register an entity reader interceptor, which enables you to intercept the input stream when reading a message body either on the client side or on the server side. This is typically useful for generic transformations of the request body, such as encryption and decryption, or compressing and decompressing.
ReaderInterceptor interface Copier lienLien copié sur presse-papiers!
The javax.ws.rs.ext.ReaderInterceptor
interface is defined as follows:
By implementing the ReaderInterceptor
interface, you can intercept the message body (Entity
object) as it is being read either on the server side or the client side. You can use an entity reader interceptor in either of the following contexts:
- Server side—if bound as a server-side interceptor, the entity reader interceptor intercepts the request message body when it is accessed by the application code (in the matched resource). Depending on the semantics of the REST request, the message body might not be accessed by the matched resource, in which case the reader interceptor is not called.
-
Client side—if bound as a client-side interceptor, the entity reader interceptor intercepts the response message body when it is accessed by the client code. If the client code does not explicitly access the response message (for example, by calling the
Response.getEntity
method), the reader interceptor is not called.
ReaderInterceptorContext interface Copier lienLien copié sur presse-papiers!
The aroundReadFrom
method of ReaderInterceptor
receives one argument of type javax.ws.rs.ext.ReaderInterceptorContext
, which can be used to access both the message body (Entity
object) and message metadata.
The ReaderInterceptorContext
interface is defined as follows:
InterceptorContext interface Copier lienLien copié sur presse-papiers!
The ReaderInterceptorContext
interface also supports the methods inherited from the base InterceptorContext
interface.
The InterceptorContext
interface is defined as follows:
Sample implementation on the client side Copier lienLien copié sur presse-papiers!
To implement an entity reader interceptor for the client side, define a class that implements the ReaderInterceptor
interface.
For example, the following code shows an example of an entity reader interceptor for the client side (with a priority of 10), which replaces all instances of COMPANY_NAME
by Red Hat
in the message body of the incoming response:
Sample implementation on the server side Copier lienLien copié sur presse-papiers!
To implement an entity reader interceptor for the server side, define a class that implements the ReaderInterceptor
interface and annotate it with the @Provider
annotation.
For example, the following code shows an example of an entity reader interceptor for the server side (with a priority of 10), which replaces all instances of COMPANY_NAME
by Red Hat
in the message body of the incoming request:
Binding a reader interceptor on the client side Copier lienLien copié sur presse-papiers!
Using the JAX-RS 2.0 client API, you can register an entity reader interceptor directly on a javax.ws.rs.client.Client
object or on a javax.ws.rs.client.WebTarget
object. Effectively, this means that the reader interceptor can optionally be applied to different scopes, so that only certain URI paths are affected by the interceptor.
For example, the following code shows how to register the SampleClientReaderInterceptor
interceptor so that it applies to all invocations made using the client
object:
For more details about registering interceptors with a JAX-RS 2.0 client, see Section 49.5, “Configuring the Client Endpoint”.
Binding a reader interceptor on the server side Copier lienLien copié sur presse-papiers!
To bind a reader interceptor on the server side (that is, to install it into the Apache CXF runtime), perform the following steps:
Add the
@Provider
annotation to the reader interceptor class, as shown in the following code fragment:Copy to Clipboard Copied! Toggle word wrap Toggle overflow When the reader interceptor implementation is loaded into the Apache CXF runtime, the REST implementation automatically scans the loaded classes to search for the classes marked with the
@Provider
annotation (the scanning phase).When defining a JAX-RS server endpoint in XML (for example, see Section 18.1, “Configuring JAX-RS Server Endpoints”), add the reader interceptor to the list of providers in the
jaxrs:providers
element.Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteThis step is a non-standard requirement of Apache CXF. Strictly speaking, according to the JAX-RS standard, the
@Provider
annotation should be all that is required to bind the interceptor. But in practice, the standard approach is somewhat inflexible and can lead to clashing providers when many libraries are included in a large project.
61.7. Entity Writer Interceptor Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
This section explains how to implement and register an entity writer interceptor, which enables you to intercept the output stream when writing a message body either on the client side or on the server side. This is typically useful for generic transformations of the request body, such as encryption and decryption, or compressing and decompressing.
WriterInterceptor interface Copier lienLien copié sur presse-papiers!
The javax.ws.rs.ext.WriterInterceptor
interface is defined as follows:
By implementing the WriterInterceptor
interface, you can intercept the message body (Entity
object) as it is being written either on the server side or the client side. You can use an entity writer interceptor in either of the following contexts:
- Server side—if bound as a server-side interceptor, the entity writer interceptor intercepts the response message body just before it is marshalled and sent back to the client.
- Client side—if bound as a client-side interceptor, the entity writer interceptor intercepts the request message body just before it is marshalled and sent out to the server.
WriterInterceptorContext interface Copier lienLien copié sur presse-papiers!
The aroundWriteTo
method of WriterInterceptor
receives one argument of type javax.ws.rs.ext.WriterInterceptorContext
, which can be used to access both the message body (Entity
object) and message metadata.
The WriterInterceptorContext
interface is defined as follows:
InterceptorContext interface Copier lienLien copié sur presse-papiers!
The WriterInterceptorContext
interface also supports the methods inherited from the base InterceptorContext
interface. For the definition of InterceptorContext
, see the section called “InterceptorContext interface”.
Sample implementation on the client side Copier lienLien copié sur presse-papiers!
To implement an entity writer interceptor for the client side, define a class that implements the WriterInterceptor
interface.
For example, the following code shows an example of an entity writer interceptor for the client side (with a priority of 10), which appends an extra line of text to the message body of the outgoing request:
Sample implementation on the server side Copier lienLien copié sur presse-papiers!
To implement an entity writer interceptor for the server side, define a class that implements the WriterInterceptor
interface and annotate it with the @Provider
annotation.
For example, the following code shows an example of an entity writer interceptor for the server side (with a priority of 10), which appends an extra line of text to the message body of the outgoing request:
Binding a writer interceptor on the client side Copier lienLien copié sur presse-papiers!
Using the JAX-RS 2.0 client API, you can register an entity writer interceptor directly on a javax.ws.rs.client.Client
object or on a javax.ws.rs.client.WebTarget
object. Effectively, this means that the writer interceptor can optionally be applied to different scopes, so that only certain URI paths are affected by the interceptor.
For example, the following code shows how to register the SampleClientReaderInterceptor
interceptor so that it applies to all invocations made using the client
object:
For more details about registering interceptors with a JAX-RS 2.0 client, see Section 49.5, “Configuring the Client Endpoint”.
Binding a writer interceptor on the server side Copier lienLien copié sur presse-papiers!
To bind a writer interceptor on the server side (that is, to install it into the Apache CXF runtime), perform the following steps:
Add the
@Provider
annotation to the writer interceptor class, as shown in the following code fragment:Copy to Clipboard Copied! Toggle word wrap Toggle overflow When the writer interceptor implementation is loaded into the Apache CXF runtime, the REST implementation automatically scans the loaded classes to search for the classes marked with the
@Provider
annotation (the scanning phase).When defining a JAX-RS server endpoint in XML (for example, see Section 18.1, “Configuring JAX-RS Server Endpoints”), add the writer interceptor to the list of providers in the
jaxrs:providers
element.Copy to Clipboard Copied! Toggle word wrap Toggle overflow NoteThis step is a non-standard requirement of Apache CXF. Strictly speaking, according to the JAX-RS standard, the
@Provider
annotation should be all that is required to bind the interceptor. But in practice, the standard approach is somewhat inflexible and can lead to clashing providers when many libraries are included in a large project.
61.8. Dynamic Binding Copier lienLien copié sur presse-papiers!
Overview Copier lienLien copié sur presse-papiers!
The standard approach to binding container filters and container interceptors to resources is to annotate the filters and interceptors with the @Provider
annotation. This ensures that the binding is global: that is, the filters and interceptors are bound to every resource class and resource method on the server side.
Dynamic binding is an alternative approach to binding on the server side, which enables you to pick and choose which resource methods your interceptors and filters are applied to. To enable dynamic binding for your filters and interceptors, you must implement a custom DynamicFeature
interface, as described here.
DynamicFeature interface Copier lienLien copié sur presse-papiers!
The DynamicFeature
interface is defined in the javax.ws.rx.container
package, as follows:
Implementing a dynamic feature Copier lienLien copié sur presse-papiers!
You implement a dynamic feature, as follows:
-
Implement one or more container filters or container interceptors, as described previously. But do not annotate them with the
@Provider
annotation (otherwise, they would be bound globally, making the dynamic feature effectively irrelevant). -
Create your own dynamic feature by implementing the
DynamicFeature
class, overriding theconfigure
method. -
In the
configure
method, you can use theresourceInfo
argument to discover which resource class and which resource method this feature is being called for. You can use this information as the basis for deciding whether or not to register some of the filters or interceptors. -
If you decide to register a filter or an interceptor with the current resource method, you can do so by invoking one of the
context.register
methods. -
Remember to annotate your dynamic feature class with the
@Provider
annotation, to ensure that it gets picked up during the scanning phase of deployment.
Example dynamic feature Copier lienLien copié sur presse-papiers!
The following example shows you how to define a dynamic feature that registers the LoggingFilter
filter for any method of the MyResource
class (or subclass) that is annotated with @GET
:
Dynamic binding process Copier lienLien copié sur presse-papiers!
The JAX-RS standard requires that the DynamicFeature.configure
method is called exactly once for each resource method. This means that every resource method could potentially have filters or interceptors installed by the dynamic feature, but it is up to the dynamic feature to decide whether to register the filters or interceptors in each case. In other words, the granularity of binding supported by the dynamic feature is at the level of individual resource methods.
FeatureContext interface Copier lienLien copié sur presse-papiers!
The FeatureContext
interface (which enables you to register filters and interceptors in the configure
method) is defined as a sub-interface of Configurable<>
, as follows:
// Java package javax.ws.rs.core; public interface FeatureContext extends Configurable<FeatureContext> { }
// Java
package javax.ws.rs.core;
public interface FeatureContext extends Configurable<FeatureContext> {
}
The Configurable<>
interface defines a variety of methods for registering filters and interceptors on a single resource method, as follows: