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
Overview
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
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
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
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
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
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
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
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
The following Java interfaces can be implemented in order to create custom REST message filters:
Interceptor classes
The following Java interfaces can be implemented in order to create custom REST message interceptors:
61.2. Container Request Filter
Overview
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
The javax.ws.rs.container.ContainerRequestFilter
interface is defined as follows:
// Java ... package javax.ws.rs.container; import java.io.IOException; public interface ContainerRequestFilter { public void filter(ContainerRequestContext requestContext) throws IOException; }
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
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:
// Java ... package javax.ws.rs.container; import java.io.InputStream; import java.net.URI; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; import javax.ws.rs.core.Cookie; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; public interface ContainerRequestContext { public Object getProperty(String name); public Collection getPropertyNames(); public void setProperty(String name, Object object); public void removeProperty(String name); public UriInfo getUriInfo(); public void setRequestUri(URI requestUri); public void setRequestUri(URI baseUri, URI requestUri); public Request getRequest(); public String getMethod(); public void setMethod(String method); public MultivaluedMap getHeaders(); public String getHeaderString(String name); public Date getDate(); public Locale getLanguage(); public int getLength(); public MediaType getMediaType(); public List getAcceptableMediaTypes(); public List getAcceptableLanguages(); public Map getCookies(); public boolean hasEntity(); public InputStream getEntityStream(); public void setEntityStream(InputStream input); public SecurityContext getSecurityContext(); public void setSecurityContext(SecurityContext context); public void abortWith(Response response); }
Sample implementation for PreMatchContainerRequest filter
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:
// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.annotation.Priority; import javax.ws.rs.ext.Provider; @PreMatching @Priority(value = 20) @Provider public class SamplePreMatchContainerRequestFilter implements ContainerRequestFilter { public SamplePreMatchContainerRequestFilter() { System.out.println("SamplePreMatchContainerRequestFilter starting up"); } @Override public void filter(ContainerRequestContext requestContext) { System.out.println("SamplePreMatchContainerRequestFilter.filter() invoked"); } }
Sample implementation for ContainerRequest filter
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:
// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.ext.Provider; import javax.annotation.Priority; @Provider @Priority(value = 30) public class SampleContainerRequestFilter implements ContainerRequestFilter { public SampleContainerRequestFilter() { System.out.println("SampleContainerRequestFilter starting up"); } @Override public void filter(ContainerRequestContext requestContext) { System.out.println("SampleContainerRequestFilter.filter() invoked"); } }
Injecting ResourceInfo
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:
// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.ext.Provider; import javax.annotation.Priority; import javax.ws.rs.core.Context; @Provider @Priority(value = 30) public class SampleContainerRequestFilter implements ContainerRequestFilter { @Context private ResourceInfo resinfo; public SampleContainerRequestFilter() { ... } @Override public void filter(ContainerRequestContext requestContext) { String resourceClass = resinfo.getResourceClass().getName(); String methodName = resinfo.getResourceMethod().getName(); System.out.println("REST invocation bound to resource class: " + resourceClass); System.out.println("REST invocation bound to resource method: " + methodName); } }
Aborting the invocation
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.
// Java package org.jboss.fuse.example; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.Provider; @PreMatching @Priority(value = 20) @Provider public class SampleAuthenticationRequestFilter implements ContainerRequestFilter { public SampleAuthenticationRequestFilter() { System.out.println("SampleAuthenticationRequestFilter starting up"); } @Override public void filter(ContainerRequestContext requestContext) { ResponseBuilder responseBuilder = null; Response response = null; String userName = requestContext.getUriInfo().getQueryParameters().getFirst("UserName"); String password = requestContext.getUriInfo().getQueryParameters().getFirst("Password"); if (authenticate(userName, password) == false) { responseBuilder = Response.serverError(); response = responseBuilder.status(Status.BAD_REQUEST).build(); requestContext.abortWith(response); } } public boolean authenticate(String userName, String password) { // Perform authentication of 'user' ... } }
Binding the server request filter
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:// Java package org.jboss.fuse.example; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.ext.Provider; import javax.annotation.Priority; @Provider @Priority(value = 30) public class SampleContainerRequestFilter implements ContainerRequestFilter { ... }
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.<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="filterProvider" /> </jaxrs:providers> <bean id="filterProvider" class="org.jboss.fuse.example.SampleContainerRequestFilter"/> </jaxrs:server> </blueprint>
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
Overview
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
The javax.ws.rs.container.ContainerResponseFilter
interface is defined as follows:
// Java ... package javax.ws.rs.container; import java.io.IOException; public interface ContainerResponseFilter { public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException; }
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
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:
// Java ... package javax.ws.rs.container; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.net.URI; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.Link; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyWriter; public interface ContainerResponseContext { public int getStatus(); public void setStatus(int code); public Response.StatusType getStatusInfo(); public void setStatusInfo(Response.StatusType statusInfo); public MultivaluedMap<String, Object> getHeaders(); public abstract MultivaluedMap<String, String> getStringHeaders(); public String getHeaderString(String name); public Set<String> getAllowedMethods(); public Date getDate(); public Locale getLanguage(); public int getLength(); public MediaType getMediaType(); public Map<String, NewCookie> getCookies(); public EntityTag getEntityTag(); public Date getLastModified(); public URI getLocation(); public Set<Link> getLinks(); boolean hasLink(String relation); public Link getLink(String relation); public Link.Builder getLinkBuilder(String relation); public boolean hasEntity(); public Object getEntity(); public Class<?> getEntityClass(); public Type getEntityType(); public void setEntity(final Object entity); public void setEntity( final Object entity, final Annotation[] annotations, final MediaType mediaType); public Annotation[] getEntityAnnotations(); public OutputStream getEntityStream(); public void setEntityStream(OutputStream outputStream); }
Sample implementation
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:
// Java package org.jboss.fuse.example; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; @Provider @Priority(value = 10) public class SampleContainerResponseFilter implements ContainerResponseFilter { public SampleContainerResponseFilter() { System.out.println("SampleContainerResponseFilter starting up"); } @Override public void filter( ContainerRequestContext requestContext, ContainerResponseContext responseContext ) { // This filter replaces the response message body with a fixed string if (responseContext.hasEntity()) { responseContext.setEntity("New message body!"); } } }
Binding the server response filter
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:// Java package org.jboss.fuse.example; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; @Provider @Priority(value = 10) public class SampleContainerResponseFilter implements ContainerResponseFilter { ... }
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.<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="filterProvider" /> </jaxrs:providers> <bean id="filterProvider" class="org.jboss.fuse.example.SampleContainerResponseFilter"/> </jaxrs:server> </blueprint>
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
Overview
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
The javax.ws.rs.client.ClientRequestFilter
interface is defined as follows:
// Java package javax.ws.rs.client; ... import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.client.ClientRequestContext; ... public interface ClientRequestFilter { void filter(ClientRequestContext requestContext) throws IOException; }
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
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:
// Java ... package javax.ws.rs.client; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.net.URI; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; import javax.ws.rs.core.Configuration; import javax.ws.rs.core.Cookie; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyWriter; public interface ClientRequestContext { public Object getProperty(String name); public Collection<String> getPropertyNames(); public void setProperty(String name, Object object); public void removeProperty(String name); public URI getUri(); public void setUri(URI uri); public String getMethod(); public void setMethod(String method); public MultivaluedMap<String, Object> getHeaders(); public abstract MultivaluedMap<String, String> getStringHeaders(); public String getHeaderString(String name); public Date getDate(); public Locale getLanguage(); public MediaType getMediaType(); public List<MediaType> getAcceptableMediaTypes(); public List<Locale> getAcceptableLanguages(); public Map<String, Cookie> getCookies(); public boolean hasEntity(); public Object getEntity(); public Class<?> getEntityClass(); public Type getEntityType(); public void setEntity(final Object entity); public void setEntity( final Object entity, final Annotation[] annotations, final MediaType mediaType); public Annotation[] getEntityAnnotations(); public OutputStream getEntityStream(); public void setEntityStream(OutputStream outputStream); public Client getClient(); public Configuration getConfiguration(); public void abortWith(Response response); }
Sample implementation
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:
// Java package org.jboss.fuse.example; import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientRequestFilter; import javax.annotation.Priority; @Priority(value = 20) public class SampleClientRequestFilter implements ClientRequestFilter { public SampleClientRequestFilter() { System.out.println("SampleClientRequestFilter starting up"); } @Override public void filter(ClientRequestContext requestContext) { System.out.println("ClientRequestFilter.filter() invoked"); } }
Aborting the invocation
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:
// Java package org.jboss.fuse.example; import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.annotation.Priority; @Priority(value = 10) public class TestAbortClientRequestFilter implements ClientRequestFilter { public TestAbortClientRequestFilter() { System.out.println("TestAbortClientRequestFilter starting up"); } @Override public void filter(ClientRequestContext requestContext) { // Test filter: aborts with BAD_REQUEST status requestContext.abortWith(Response.status(Status.BAD_REQUEST).build()); } }
Registering the client request filter
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
.
// Java ... import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; ... Client client = ClientBuilder.newClient(); client.register(new SampleClientRequestFilter()); WebTarget target = client .target("http://localhost:8001/rest/TestAbortClientRequest"); target.register(new TestAbortClientRequestFilter());
61.5. Client Response Filter
Overview
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
The javax.ws.rs.client.ClientResponseFilter
interface is defined as follows:
// Java package javax.ws.rs.client; ... import java.io.IOException; public interface ClientResponseFilter { void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException; }
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
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:
// Java ... package javax.ws.rs.client; import java.io.InputStream; import java.net.URI; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.Link; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; public interface ClientResponseContext { public int getStatus(); public void setStatus(int code); public Response.StatusType getStatusInfo(); public void setStatusInfo(Response.StatusType statusInfo); public MultivaluedMap<String, String> getHeaders(); public String getHeaderString(String name); public Set<String> getAllowedMethods(); public Date getDate(); public Locale getLanguage(); public int getLength(); public MediaType getMediaType(); public Map<String, NewCookie> getCookies(); public EntityTag getEntityTag(); public Date getLastModified(); public URI getLocation(); public Set<Link> getLinks(); boolean hasLink(String relation); public Link getLink(String relation); public Link.Builder getLinkBuilder(String relation); public boolean hasEntity(); public InputStream getEntityStream(); public void setEntityStream(InputStream input); }
Sample implementation
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:
// Java package org.jboss.fuse.example; import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientResponseContext; import javax.ws.rs.client.ClientResponseFilter; import javax.annotation.Priority; @Priority(value = 20) public class SampleClientResponseFilter implements ClientResponseFilter { public SampleClientResponseFilter() { System.out.println("SampleClientResponseFilter starting up"); } @Override public void filter( ClientRequestContext requestContext, ClientResponseContext responseContext ) { // Add an extra header on the response responseContext.getHeaders().putSingle("MyCustomHeader", "my custom data"); } }
Registering the client response filter
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:
// Java ... import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; ... Client client = ClientBuilder.newClient(); client.register(new SampleClientResponseFilter());
61.6. Entity Reader Interceptor
Overview
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
The javax.ws.rs.ext.ReaderInterceptor
interface is defined as follows:
// Java ... package javax.ws.rs.ext; public interface ReaderInterceptor { public Object aroundReadFrom(ReaderInterceptorContext context) throws java.io.IOException, javax.ws.rs.WebApplicationException; }
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
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:
// Java ... package javax.ws.rs.ext; import java.io.IOException; import java.io.InputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedMap; public interface ReaderInterceptorContext extends InterceptorContext { public Object proceed() throws IOException, WebApplicationException; public InputStream getInputStream(); public void setInputStream(InputStream is); public MultivaluedMap<String, String> getHeaders(); }
InterceptorContext interface
The ReaderInterceptorContext
interface also supports the methods inherited from the base InterceptorContext
interface.
The InterceptorContext
interface is defined as follows:
// Java ... package javax.ws.rs.ext; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Collection; import javax.ws.rs.core.MediaType; public interface InterceptorContext { public Object getProperty(String name); public Collection<String> getPropertyNames(); public void setProperty(String name, Object object); public void removeProperty(String name); public Annotation[] getAnnotations(); public void setAnnotations(Annotation[] annotations); Class<?> getType(); public void setType(Class<?> type); Type getGenericType(); public void setGenericType(Type genericType); public MediaType getMediaType(); public void setMediaType(MediaType mediaType); }
Sample implementation on the client side
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:
// Java package org.jboss.fuse.example; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.ReaderInterceptor; import javax.ws.rs.ext.ReaderInterceptorContext; @Priority(value = 10) public class SampleClientReaderInterceptor implements ReaderInterceptor { @Override public Object aroundReadFrom(ReaderInterceptorContext interceptorContext) throws IOException, WebApplicationException { InputStream inputStream = interceptorContext.getInputStream(); byte[] bytes = new byte[inputStream.available()]; inputStream.read(bytes); String responseContent = new String(bytes); responseContent = responseContent.replaceAll("COMPANY_NAME", "Red Hat"); interceptorContext.setInputStream(new ByteArrayInputStream(responseContent.getBytes())); return interceptorContext.proceed(); } }
Sample implementation on the server side
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:
// Java package org.jboss.fuse.example; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.ReaderInterceptor; import javax.ws.rs.ext.ReaderInterceptorContext; @Priority(value = 10) @Provider public class SampleServerReaderInterceptor implements ReaderInterceptor { @Override public Object aroundReadFrom(ReaderInterceptorContext interceptorContext) throws IOException, WebApplicationException { InputStream inputStream = interceptorContext.getInputStream(); byte[] bytes = new byte[inputStream.available()]; inputStream.read(bytes); String requestContent = new String(bytes); requestContent = requestContent.replaceAll("COMPANY_NAME", "Red Hat"); interceptorContext.setInputStream(new ByteArrayInputStream(requestContent.getBytes())); return interceptorContext.proceed(); } }
Binding a reader interceptor on the client side
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:
// Java ... import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; ... Client client = ClientBuilder.newClient(); client.register(SampleClientReaderInterceptor.class);
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
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:// Java package org.jboss.fuse.example; ... import javax.annotation.Priority; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.ReaderInterceptor; import javax.ws.rs.ext.ReaderInterceptorContext; @Priority(value = 10) @Provider public class SampleServerReaderInterceptor implements ReaderInterceptor { ... }
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.<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="interceptorProvider" /> </jaxrs:providers> <bean id="interceptorProvider" class="org.jboss.fuse.example.SampleServerReaderInterceptor"/> </jaxrs:server> </blueprint>
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
Overview
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
The javax.ws.rs.ext.WriterInterceptor
interface is defined as follows:
// Java ... package javax.ws.rs.ext; public interface WriterInterceptor { void aroundWriteTo(WriterInterceptorContext context) throws java.io.IOException, javax.ws.rs.WebApplicationException; }
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
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:
// Java ... package javax.ws.rs.ext; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedMap; public interface WriterInterceptorContext extends InterceptorContext { void proceed() throws IOException, WebApplicationException; Object getEntity(); void setEntity(Object entity); OutputStream getOutputStream(); public void setOutputStream(OutputStream os); MultivaluedMap<String, Object> getHeaders(); }
InterceptorContext interface
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
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:
// Java package org.jboss.fuse.example; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) public class SampleClientWriterInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext interceptorContext) throws IOException, WebApplicationException { OutputStream outputStream = interceptorContext.getOutputStream(); String appendedContent = "\nInterceptors always get the last word in."; outputStream.write(appendedContent.getBytes()); interceptorContext.setOutputStream(outputStream); interceptorContext.proceed(); } }
Sample implementation on the server side
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:
// Java package org.jboss.fuse.example; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) @Provider public class SampleServerWriterInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext interceptorContext) throws IOException, WebApplicationException { OutputStream outputStream = interceptorContext.getOutputStream(); String appendedContent = "\nInterceptors always get the last word in."; outputStream.write(appendedContent.getBytes()); interceptorContext.setOutputStream(outputStream); interceptorContext.proceed(); } }
Binding a writer interceptor on the client side
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:
// Java ... import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; ... Client client = ClientBuilder.newClient(); client.register(SampleClientReaderInterceptor.class);
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
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:// Java package org.jboss.fuse.example; ... import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) @Provider public class SampleServerWriterInterceptor implements WriterInterceptor { ... }
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.<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="interceptorProvider" /> </jaxrs:providers> <bean id="interceptorProvider" class="org.jboss.fuse.example.SampleServerWriterInterceptor"/> </jaxrs:server> </blueprint>
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
Overview
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
The DynamicFeature
interface is defined in the javax.ws.rx.container
package, as follows:
// Java package javax.ws.rs.container; import javax.ws.rs.core.FeatureContext; import javax.ws.rs.ext.ReaderInterceptor; import javax.ws.rs.ext.WriterInterceptor; public interface DynamicFeature { public void configure(ResourceInfo resourceInfo, FeatureContext context); }
Implementing a dynamic feature
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
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
:
// Java ... import javax.ws.rs.container.DynamicFeature; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.FeatureContext; import javax.ws.rs.ext.Provider; @Provider public class DynamicLoggingFilterFeature implements DynamicFeature { @Override void configure(ResourceInfo resourceInfo, FeatureContext context) { if (MyResource.class.isAssignableFrom(resourceInfo.getResourceClass()) && resourceInfo.getResourceMethod().isAnnotationPresent(GET.class)) { context.register(new LoggingFilter()); } }
Dynamic binding process
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
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> { }
The Configurable<>
interface defines a variety of methods for registering filters and interceptors on a single resource method, as follows:
// Java ... package javax.ws.rs.core; import java.util.Map; public interface Configurable<C extends Configurable> { public Configuration getConfiguration(); public C property(String name, Object value); public C register(Class<?> componentClass); public C register(Class<?> componentClass, int priority); public C register(Class<?> componentClass, Class<?>... contracts); public C register(Class<?> componentClass, Map<Class<?>, Integer> contracts); public C register(Object component); public C register(Object component, int priority); public C register(Object component, Class<?>... contracts); public C register(Object component, Map<Class<?>, Integer> contracts); }