Filtering requests and responses can provide useful functionality that is hidden from the application layer of building and sending requests, and processing responses. Filters can read/modify the request URI, headers and entity or read/modify the response status, headers and entity.
The Client
and WebResource
classes extend from Filterable and that enables the addition of ClientFilter instances. A WebResource
will inherit filters from its creator, which can be a Client
or another WebResource
. Additional filters can be added to a WebResource
after it has been created. For requests, filters are applied in reverse order, starting with the WebResource
filters and then moving to the inherited filters. For responses, filters are applied in order, starting with inherited filters and followed by the filters added to the WebResource
. All filters are applied in the order in which they were added. For instance, in the following example the Client
has two filters added, filter1
and filter2
, in that order, and the WebResource
has one filter added, filter3
:
ClientFilter filter1 = ... ClientFilter filter2 = ... Client c = Client.create(); c.addFilter(filter1); c.addFilter(filter2); ClientFilter filter3 = ... WebResource r = c.resource(...); r.addFilter(filter3);
After a request has been built the request is filtered by filter3
, filter2
and filter1
in that order. After the response has been received the response is filtered by filter1
, filter2
and filter3
in that order, before the response is returned.
Filters are implemented using the “russian doll” stack-based pattern where a filter is responsible for calling the next filter in the ordered list of filters (or the next filter in the “chain” of filters). The basic template for a filter is as follows:
class AppClientFilter extends ClientFilter { public ClientResponse handle(ClientRequest cr) { // Modify the request ClientRequest mcr = modifyRequest(cr); // Call the next filter ClientResponse resp = getNext().handle(mcr); // Modify the response return modifyResponse(resp); } }
The filter modifies the request (if required) by creating a new ClientRequest or modifying the state of the passed ClientRequest before calling the next filter. The call to the next request will return the response, a ClientResponse. The filter modifies the response (if required) by creating a new ClientResponse or modifying the state of the returned ClientResponse. Then the filter returns the modified response. Filters are re-entrant and may be called by multiple threads performing requests and processing responses.
Supported filters
The Jersey Client API currently supports two filters:
- A GZIP content encoding filter, GZIPContentEncodingFilter. If this filter is added then a request entity is compressed with the
Content-Encoding
ofgzip
, and a response entity if compressed with aContent-Encoding
ofgzip
is decompressed. The filter declares anAccept-Encoding
ofgzip
. - A logging filter, LoggingFilter. If this filter is added then the request and response headers as well as the entities are logged to a declared output stream if present, or to
System.out
if not. Often this filter will be placed at the end of the ordered list of filters to log the request before it is sent and the response after it is received.
The filters above are good examples that show how to modify or read request and response entities. Refer to the source code of the Jersey client for more details.