Search code examples
javajerseyjax-rscache-controlrestful-architecture

Jersey Cache Control for each Resource


Is it somehow possible to define cache control level for each resource?

Is there some annotation i could put on top of each Resource class so to specify cache control in a custom way?


Solution

  • To solve this issue I ended up defining an @Cache aspect. There are a couple of caveats that I ran into:

    • The cached method needs to return a Response object (not POJOs) so that the aspect can modify the headers.

    • If you want to use ETags then the class containing the method (or the method arguments themselves) needs to expose the @Request so that the aspect can inspect the incoming tag.

    • Make sure that your method arguments combined with your method name will in fact create unique keys. Another catch here is response type. The client may issue two requests with identical parameters but different response types.

    • You could easily add options to the aspect to control max-age and other parameters on a per-method basis.

    Here's my invoke method:

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
      if (Response.class != invocation.getMethod().getReturnType()) {
        logger.warning(String.format("%s is @Cachable but does not return a Response object", invocation.getMethod()));
        return invocation.proceed();
      }
    
      Optional<Request> request = getRequest(invocation);
      if (!request.isPresent()) {
        logger.warning(String.format("%s is @Cachable but does not declare a public Request field named \"request\"", invocation.getMethod()));
        return invocation.proceed();
      }
    
      Object response = super.invoke(invocation);
      EntityTag responseTag = JaxRsUtil.getEntityTag(response);
    
      Response.ResponseBuilder builder = request.get().evaluatePreconditions(responseTag);
      if (null != builder) {
        logger.finer("Found matching etag: " + responseTag);
        return builder.build();
      } 
      CacheControl cc = new CacheControl();
      cc.setMaxAge(maxAge);
      builder = Response.fromResponse((Response)response).tag(responseTag).cacheControl(cc);
      return builder.build();
    }