我怎样才能在新泽西ContainerResponseFilter资源注解 [英] How can I get resource annotations in a Jersey ContainerResponseFilter

查看:1018
本文介绍了我怎样才能在新泽西ContainerResponseFilter资源注解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

新泽西提供了两个类与资源互动的注释:


  • ResourceFilterFactory,一个类可以继承它来触发一次应用程序启动时

  • ContainerRequestFilter, <一href=\"http://jersey.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/spi/container/ContainerResponseFilter.html\">ContainerResponseFilter,几类可以继承他们能够在每次请求/响应
  • 触发

ResourceFilterFactory定义了一个创建办法(实行),该采取 AbstractMethod 它可以访问方法和类的注解

ContainerRequestFilter和ContainerResponseFilter定义了一个过滤器办法(实行)称取请求/响应,但那些给完全访问调用方法的注释,而不是类之一。

我想实现一个CacheControl注解定义HTTP缓存头下面的方式。

  @Path(/路径)
@CacheControl(MAXAGE = 172800)
公共类资源
{
    @得到
    @Path(/(编号))
    @CacheControl(mustRevalidate =真)
    市民反应的get(@PathParam(ID)长ID)
    {
        ...
    }
}


我的问题是,我不希望创建一个新的CacheControlFilter在我的应用程序定义的每一个REST方法

 公共类FilterFactory实现ResourceFilterFactory
{
    @覆盖
    公开名单&LT; ResourceFilter&GT;创建(AbstractMethod法)
    {
        清单&LT; ResourceFilter&GT;过滤器= newArrayList();
        如果(isAnnotation present(方法,CacheControl.class))
            filters.add(新CacheControlFilter(方法));
        返回过滤器;
    }    私人布尔isAnnotation present(AbstractMethod方法,类&LT ;?扩展注解&GT; clazz所)
    {
        返回method.isAnnotation present(clazz所)|| method.getResource()isAnnotation present(clazz所)。
    }
}


是否有访问方式 AbstractMethod 无实例化一个CacheContronlFilter每REST方法?

 公共类CacheControlFilter实现ResourceFilter,ContainerResponseFilter
{
    私人AbstractMethod方法;    公共CacheControlFilter(AbstractMethod法)
    {
        this.method =方法;
    }    @覆盖
    公共ContainerResponse过滤器(ContainerRequest要求,ContainerResponse响应)
    {
        putCacheControlIfExists(响应,method.getAnnotations());
        putCacheControlIfExists(响应,method.getResource()getAnnotations());
        返回响应;
    }    私人无效putCacheControlIfExists(ContainerResponse响应,注释[]注释)
    {
        CacheControl注释= findCacheControl(注释);
        如果(注释!= NULL)
            。response.getHttpHeaders()把(CACHE_CONTROL,createCacheControlHeader(注释));
    }    私人CacheControl findCacheControl(译注[]注释)
    {
        对于(译注注解:注解)
            如果(注释的instanceof CacheControl)
                回报(CacheControl)注释;
        返回null;
    }    私人列表&LT;对象&gt; createCacheControlHeader(CacheControl注释)
    {
        javax.ws.rs.core.CacheControl头=新javax.ws.rs.core.CacheControl();
        header.setMaxAge(annotation.maxAge());
        header.setMustRevalidate(annotation.mustRevalidate());
        header.setNoCache(annotation.noCache());
        header.setNoStore(annotation.noStore());
        header.setNoTransform(annotation.noTransform());
        header.setProxyRevalidate(annotation.proxyRevalidate());
        返回列表&LT;对象&gt; newArrayList(Splitter.on(''),斯普利特(header.toString()));
    }    @覆盖
    公共ContainerRequestFilter getRequestFilter()
    {
        返回null;
    }    @覆盖
    公共ContainerResponseFilter getResponseFilter()
    {
        返回此;
    }
}


解决方案

为什么是重要的没有过滤器的一个单独的实例为每个应用的方法?可能有大量的并发访问,所以如果你不希望这些是独立的情况下,他们将不得不是可变的,你将不得不进入threadlocals混乱(存储目前适用于定线程抽象方法)。不知道如果这是你真正想要的。其每一个单独的对象是不贵。

更新:另外请注意,你不希望创建的每个方式的新实例。你只想做它与连接到他们或他们的资源,对任何@CacheControl注释的方法呢?你还可以共享滤波器实例为共同@C​​acheControl值 - 即,如果一个方法使用相同的超高速缓存控制设置为某些其他方法中,重复使用的相同的过滤器,如果没有,创建过滤器用于该方法的一个单独的实例。换句话说 - 你可以有每相对于每个方法一个过滤器一个明显的Cache-Control设置一个过滤器 - 只要你不真正关心的方法 - 你在乎它相连的注释

Jersey offers two classes to interact with annotations on resources:

ResourceFilterFactory defines a create method (to implement) that take an AbstractMethod which gives access to methods and classes annotations.

ContainerRequestFilter and ContainerResponseFilter defines a filter method (to implement) that take request/response but those give solely access to the called method annotation, not the class one.

I'm trying to implement a CacheControl annotation that defines HTTP cache headers the following way.

@Path("/path")
@CacheControl(maxAge = 172800)
public class Resource
{   
    @GET
    @Path("/{id}")
    @CacheControl(mustRevalidate = true)
    public Response get(@PathParam("id") Long id)
    {
        ...
    }
}


My problem is that I don't want to create a new CacheControlFilter for every REST method defined in my application.

public class FilterFactory implements ResourceFilterFactory
{    
    @Override
    public List<ResourceFilter> create(AbstractMethod method)
    {
        List<ResourceFilter> filters = newArrayList();
        if (isAnnotationPresent(method, CacheControl.class))
            filters.add(new CacheControlFilter(method));
        return filters;
    }

    private boolean isAnnotationPresent(AbstractMethod method, Class<? extends Annotation> clazz)
    {
        return method.isAnnotationPresent(clazz) || method.getResource().isAnnotationPresent(clazz);
    }
}


Is there a way to access the AbstractMethod without instancing a CacheContronlFilter for every REST method?

public class CacheControlFilter implements ResourceFilter, ContainerResponseFilter
{
    private AbstractMethod method;

    public CacheControlFilter(AbstractMethod method)
    {
        this.method = method;
    }

    @Override
    public ContainerResponse filter(ContainerRequest request, ContainerResponse response)
    {
        putCacheControlIfExists(response, method.getAnnotations());
        putCacheControlIfExists(response, method.getResource().getAnnotations());
        return response;
    }

    private void putCacheControlIfExists(ContainerResponse response, Annotation[] annotations)
    {
        CacheControl annotation = findCacheControl(annotations);
        if (annotation != null)
            response.getHttpHeaders().put(CACHE_CONTROL, createCacheControlHeader(annotation));
    }

    private CacheControl findCacheControl(Annotation[] annotations)
    {
        for (Annotation annotation : annotations)
            if (annotation instanceof CacheControl)
                return (CacheControl) annotation;
        return null;
    }

    private List<Object> createCacheControlHeader(CacheControl annotation)
    {
        javax.ws.rs.core.CacheControl header = new javax.ws.rs.core.CacheControl();
        header.setMaxAge(annotation.maxAge());
        header.setMustRevalidate(annotation.mustRevalidate());
        header.setNoCache(annotation.noCache());
        header.setNoStore(annotation.noStore());
        header.setNoTransform(annotation.noTransform());
        header.setProxyRevalidate(annotation.proxyRevalidate());
        return Lists.<Object> newArrayList(Splitter.on(',').split(header.toString()));
    }

    @Override
    public ContainerRequestFilter getRequestFilter()
    {
        return null;
    }

    @Override
    public ContainerResponseFilter getResponseFilter()
    {
        return this;
    }
}

解决方案

Why is it important to not have a separate instance of the filter for every applicable method? There may be a lot of concurrent access, so if you don't want these to be separate instances, they would have to be mutable and you would have to get into the threadlocals mess (to store the abstract method currently applicable for the given thread). Not sure if that's what you really want. Having a separate object for each is not that expensive.

UPDATE: Also note, you don't want to create a new instance for every method. You just want to do it for methods with any @CacheControl annotation attached to them or to their resources, right? Also you can share filter instances for common @CacheControl values - i.e. if a method uses the same cache control setting as some other method, reuse the same filter for that, if not, create a separate instance of the filter for that method. In other words - you can have one filter per one distinct cache-control setting as opposed to one filter per method - as you don't really care about the method - you care about the annotations attached to it.

这篇关于我怎样才能在新泽西ContainerResponseFilter资源注解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆