Chapter 62. 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.
62.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 62.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 62.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:
-
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
Figure 62.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 62.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:
-
ClientRequestfilter -
WriteInterceptor -
ClientResponsefilter -
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:
62.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.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 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
@Providerannotation 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
@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.<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
@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.
62.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
@Providerannotation 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
@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.<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
@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.
62.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());62.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());
62.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.getEntitymethod), 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 50.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
@Providerannotation 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
@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.<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
@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.
62.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 50.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
@Providerannotation 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
@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.<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
@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.
62.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
@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
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);
}
Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.