Binding JAX-RS Providers to Resource Methods

When you register providers (such as filters and interceptors) in your application they’re associated and applied to each resource method by default. In other words they’re bound globally. For most cases this approach is sufficient but sometimes, especially when you want to use your provider only with a few methods, it’s not enough. JAX-RS 2.0 brings a solution for this situation: Name and Dynamic Binding.

Name Binding

Name Binding is an annotation-driven (static) provider binding based on the JAX-RS meta-annotation @NameBinding. Custom binding annotations annotated with @NameBinding can be later used to decorate resource classes or resource methods as well as JAX-RS providers to define associations between them.

Let’s assume we have a logging filter (similar to LoggingFilter) responsible for logging incoming and outgoing communication (headers and/or entity) on our server:

@Provider
@Logged
public class LoggingFilter implements ContainerRequestFilter,
                                      ContainerResponseFilter { ... }

Decorating this class with @Logged (name binding) annotation we transformed a globally-bound provider to a name-bound one. To bind this provider to a resource method we need to decorate the method with @Logged as well:

@Path("helloworld")
public class HelloWorldResource {

    @GET
    @Produces("text/plain")
    @Logged
    public String getHello() {
        return "Hello World!";
    }
}

Name binding annotations can be applied to a resource method (as in our case), to a resource class (i.e. HelloWorldResource) or to an Application sub-class (a name-bound JAX-RS provider bound by the annotation will be applied to all (sub-)resource methods).

Finally to create a name binding annotation from @Logged just put @NameBinding on top of it:

@NameBinding
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Logged { }

Assigning multiple name-bound providers to a single resource method is also possible by decorating the method with all required name binding annotations. For example, if you want to use AuthenticationFilter:

@Provider
@Authenticated
public class AuthenticationFilter implements ContainerRequestFilter { ... }

with the previously mentioned HelloWorldResource.getHello() resource method decorate this method with @Authenticated as well. Now both AuthenticationFilter and LoggingFilter will be used when the resource method is being invoked.

Dynamic Binding

To bind post-matching providers more dynamically a new interface, DynamicFeature, has been introduced in JAX-RS 2.0. By implementing this interface you can assign particular providers programmatically to a subset of available resource methods.

Similar mechanism exists in Jersey 1. ResourceFilterFactory / ResourceFilter allows you to create request/response filters for a resource method. These classes has been replaced with DynamicFeature in Jersey 2.

The interface contains a callback method providing

The callback method is invoked once for every resource method, that exists in an application, to augment the set of filters and entity interceptors bound to this method.

Let’s take the example from the previous chapter and assign LoggingFilter to all resource methods from package my.package.admin that are listening to HTTP GET requests.

@Provider
public class MyDynamicFeature implements DynamicFeature {

    @Override
    public void configure(final ResourceInfo resourceInfo,
                          final FeatureContext context) {

        final String resourcePackage = resourceInfo.getResourceClass()
                .getPackage().getName();
        final Method resourceMethod = resourceInfo.getResourceMethod();

        if ("my.package.admin".equals(resourcePackage)
                && resourceMethod.getAnnotation(GET.class) != null) {
            context.register(LoggingFilter.class);
        }
    }
}

Now every HTTP GET request sent to a resource from my.package.admin package will be logged.

Implementations of DynamicFeature contract are still providers that need to be registered in your application before they can be used. Registering Resources and Providers in Jersey 2 discusses how to do that.

Further reading

References