Using name binding annotations in Jersey
Solution 1:
Name binding
Name binding is a concept that allows to say to a JAX-RS runtime that a specific filter or interceptor will be executed only for a specific resource method. When a filter or an interceptor is limited only to a specific resource method we say that it is name-bound. Filters and interceptors that do not have such a limitation are called global.
Defining a name binding annotation
Filters or interceptors can be assigned to a resource method using the @NameBinding
annotation. This annotation is used as meta annotation for other user implemented annotations that are applied to a providers and resource methods. See the following example:
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {}
The example above defines a new @Compress
annotation which is a name binding annotation as it is annotated with @NameBinding
. The @Compress
annotation can be used to bind filters and interceptor to endpoints.
Binding a filter or interceptor to an endpoint
Consider you have an interceptor that performs GZIP compression and you want to bind such interceptor to a resource method. To do it, annotate both the resource method and the interceptor, as following:
@Compress
public class GZIPWriterInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
final OutputStream outputStream = context.getOutputStream();
context.setOutputStream(new GZIPOutputStream(outputStream));
context.proceed();
}
}
@Path("helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String getHello() {
return "Hello World!";
}
@GET
@Path("too-much-data")
@Compress
public String getVeryLongString() {
String str = ... // very long string
return str;
}
}
The @Compress
is applied on the resource method getVeryLongString()
and on the interceptor GZIPWriterInterceptor
. The interceptor will be executed only if any resource method with such a annotation will be executed.
In above example, the interceptor will be executed only for the getVeryLongString()
method. The interceptor will not be executed for method getHello()
. In this example the reason is probably clear. We would like to compress only long data and we do not need to compress the short response of "Hello World!"
.
Name binding can be applied on a resource class. In the example HelloWorldResource
would be annotated with @Compress
. This would mean that all resource methods will use compression in this case.
Note that global filters are executed always, so even for resource methods which have any name binding annotations.
Documentation
@NameBinding
annotation documentation- Jersey documentation about filters and interceptors
Examples
- Logging HTTP requests and responses using filters and name binding annotations
- Token-based authentication using filters and name binding annotations
- Using interceptors and name binding annotations to add a property to a JSON with Jackson
- Filters with name binding for security purposes