Dieser Inhalt ist in der von Ihnen ausgewählten Sprache nicht verfügbar.
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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
In the server processing pipeline, you can add a filter (or interceptor) at any of the following extension points:
-
PreMatchContainerRequestfilter -
ContainerRequestfilter -
ReadInterceptor -
ContainerResponsefilter -
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
In the client processing pipeline, you can add a filter (or interceptor) at any of the following extension points:
-
ClientRequestfilter -
WriteInterceptor -
ClientResponsefilter -
ReadInterceptor
Filter and interceptor order Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
The following Java interfaces can be implemented in order to create custom REST message filters:
Interceptor classes Link kopierenLink in die Zwischenablage kopiert!
The following Java interfaces can be implemented in order to create custom REST message interceptors:
61.2. Container Request Filter Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
To bind a server request filter (that is, to install it into the Apache CXF runtime), perform the following steps:
Add the
@Providerannotation 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
@Providerannotation (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:providerselement.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
@Providerannotation 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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
To bind a server response filter (that is, to install it into the Apache CXF runtime), perform the following steps:
Add the
@Providerannotation 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
@Providerannotation (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:providerselement.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
@Providerannotation 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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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.getEntitymethod), the reader interceptor is not called.
ReaderInterceptorContext interface Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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
@Providerannotation 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
@Providerannotation (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:providerselement.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
@Providerannotation 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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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
@Providerannotation 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
@Providerannotation (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:providerselement.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
@Providerannotation 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 Link kopierenLink in die Zwischenablage kopiert!
Overview Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
The DynamicFeature interface is defined in the javax.ws.rx.container package, as follows:
Implementing a dynamic feature Link kopierenLink in die Zwischenablage kopiert!
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
@Providerannotation (otherwise, they would be bound globally, making the dynamic feature effectively irrelevant). -
Create your own dynamic feature by implementing the
DynamicFeatureclass, overriding theconfiguremethod. -
In the
configuremethod, you can use theresourceInfoargument 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.registermethods. -
Remember to annotate your dynamic feature class with the
@Providerannotation, to ensure that it gets picked up during the scanning phase of deployment.
Example dynamic feature Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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 Link kopierenLink in die Zwischenablage kopiert!
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: