Как я могу получить аннотации ресурсов в Jersey ContainerResponseFilter - PullRequest
10 голосов
/ 29 ноября 2011

Джерси предлагает два класса для взаимодействия с аннотациями на ресурсах:

  • ResourceFilterFactory , один класс может наследовать его для запуска один раз при запуске приложения
  • ContainerRequestFilter , ContainerResponseFilter , несколько классов могут наследовать их для запуска при каждом запросе / ответе

ResourceFilterFactory определяет create метод (для реализации), который принимает AbstractMethod, который предоставляет доступ к методам и аннотациям классов.

ContainerRequestFilter и ContainerResponseFilter определяют метод filter (для реализации), который принимает запрос / ответ, но предоставляет только доступ к аннотации вызываемого метода, а не к классу один.

Я пытаюсь реализовать аннотацию CacheControl, которая определяет заголовки кэша HTTP следующим образом.

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

Моя проблема в том, что я не хочу создавать новый CacheControlFilter для каждого метода REST, определенного в моем приложении .

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);
    }
}

Есть ли способ получить доступ к AbstractMethod без создания экземпляра CacheContronlFilter для каждого метода REST?

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;
    }
}

1 Ответ

4 голосов
/ 02 декабря 2011

Почему важно не иметь отдельный экземпляр фильтра для каждого применимого метода? Одновременного доступа может быть много, поэтому, если вы не хотите, чтобы они были отдельными экземплярами, они должны быть изменяемыми, и вам нужно было бы попасть в беспорядок локальных потоков (чтобы сохранить абстрактный метод, который в настоящее время применим для данного потока ). Не уверен, что ты действительно этого хочешь. Наличие отдельного объекта для каждого не так уж и дорого.

ОБНОВЛЕНИЕ: Также обратите внимание, что вы не хотите создавать новый экземпляр для каждого метода. Вы просто хотите сделать это для методов с любой аннотацией @CacheControl, прикрепленной к ним или к их ресурсам, верно? Также вы можете поделиться экземплярами фильтра для общих значений @CacheControl - то есть, если метод использует ту же настройку управления кэшем, что и какой-либо другой метод, повторно используйте тот же фильтр для этого, если нет, создайте отдельный экземпляр фильтра для этого метода. Другими словами - у вас может быть один фильтр на каждую отдельную настройку управления кэшем, в отличие от одного фильтра на метод - так как вы на самом деле не заботитесь о методе - вы заботитесь о прикрепленных к нему аннотациях.

...