Using name binding annotations in Jersey

2019-01-09 02:28发布

问题:

How does the @NameBinding annotation work in Jersey to apply a filter on particular resource methods or resource class?

Consider the following annotation:

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

How does it work?

回答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


标签: java rest jersey