Skip to main content
Last updated November 08, 2011 16:40, by spericas
Feedicon  

Filters and Handlers Revisited


Make Global Binding the Default

Drop support for @GlobalBinding and make this binding the default for all filters and handler classes that are only annotated with @Provider. If a filter or handler is decorated with an annotation derived from @NameBinding, they are considered local not global.

ResourceInfo

Allow injection of a new class ResourceInfo that will provide resource class and method information. This information will be removed from FilterContext --thus, removing the BaseContext class. For example:

@Provider
public class LoggingFilter implements RequestFilter  {
    public RequestFilter(@Context ResourceInfo ri) { ... }
    ...
}

Note that as explained in Section 9.1 of the spec, the instance injected must be capable of selecting the correct Resourceinfo during a request-response cycle. Injection of ResourceInfo is only supported as part of the server API.

Pre-Match Filters

A new interface is proposed to support the new PreMatch extension point. Filters defined for this extension point will be executed before resource matching and are, therefore, capable of altering the outcome of the JAX-RS matching algorithm (e.g., by updating the HTTP method in the request). This interface will use the same FilterContext as RequestFilter and ResponseFilter.

@Provider
public class HttpMethodOverrideFilter implements PreMatchRequestFilter {
    FilterAction preMatchFilter(FilterContext ctx) throws IOException { ... }
}

Restrictions:

  • Server API only
  • Pre-match filters are global in nature, any name binding derived annotations on the filter class are ignored
  • The DynamicBinding interface is also ignored
  • Only handlers that are bound globally will be executed whenever a pre-match filter reads or writes an entity (which should be rare)
  • During the pre-match phase, methods of an injected ResourceInfo will return null

If a filter needs to be executed before and after resource matching, it can implement the corresponding interfaces. For example, a logging filter may be installed before and after matching:

@Provider
public class LoggingFilter implements RequestFilter, PreMatchRequestFilter {
    FilterAction preFilter(FilterContext ctx) throws IOException { 
        logRequest(ctx.getRequest());
    }
    FilterAction preMatchFilter(FilterContext ctx) throws IOException {
        logRequest(ctx.getRequest());
    }
}

Just like other filters, pre-match filters must be sorted by binding priorities (@BindingPriority) --but there is no way to specify a binding priority that is different pre and post matching for those filters that are part of both chains.

Single Class, Multiple Filters

As seen in the last section, it is possible for a single class to implement multiple filters. Let's take a look at a few examples:

@Provider
@Logged
public class LoggingFilter implements RequestFilter, PreMatchRequestFilter {
    ...
}

This filter uses name binding via @Logged. However, as stated above, this annotation will be ignore during the pre-match phase, so this filter will be part pre-match chain in all requests, as well as in the post-match chain for all resource methods decorated with @Logged.

@Provider
public class LoggingFilter implements RequestFilter, DynamicBinding, PreMatchRequestFilter {
    ...
}

In this example, the DynamicBinding interface only applies to RequestFilter, as stated above it is ignore in the pre-match phase. This filter will be part of the pre-match chain for all requests, as well as the post-match chain for all resource methods for which DynamicBinding.isBound() returns true at deploy time.

For the sake of clarity, it should be recommended that classes implementing PreMatchRequestFilter do not implement any other interfaces. Also, it should be recommended to use pre-match filters only when the input to the matching algorithm needs to be modified.

JAX-RS 2.0 Pipeline

Putting it all together, the server-side pipeline (naturally, no support for pre-match binding on client side) would look like this:

 
 
Close
loading
Please Confirm
Close