How to cache an answer with jersey?

I am trying to develop a soothing API using Jersey. I have a GET API for a specific receive operation that GET is receiving at the same time from the same client. Is it possible to cache the response? Any pointers are appreciated.

thanks

+7
source share
3 answers

You can use CacheControl, eTag - follow the sample code below

// In your jersey method final EntityTag eTag = new EntityTag(resource.getId() + "_" + resource.getLastModified().getTime()); final CacheControl cacheControl = new CacheControl(); cacheControl.setMaxAge(-1); ResponseBuilder builder = request.evaluatePreconditions( resource.getLastModified(), eTag); // the resoruce information was modified, return it if (builder == null) { builder = Response.ok(resource); } // the resource information was not modified, return a 304 return builder.cacheControl(cacheControl).lastModified( resource.getLastModified()).tag(eTag).build(); 

Replace resource instance.

+10
source

Summary of solutions:

  • Request as a method parameter

    Interface:

     @Path("myentity") public interface MyEntityResource @GET @Produces(MediaType.APPLICATION_JSON) public Response getMyEntity(@Context final Request request); } 

    Implementation:

     public class MyEntityResourceImpl implements MyEntityResource @Override public Response getMyEntity(final Request request) { final MyEntity myEntity = ... // load entity final String eTagValue = ... // calclutate value of ETag final EntityTag eTag = new EntityTag(eTagValue); ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag); if (responseBuilder == null) { return Response.ok(user).tag(eTag).build(); } return responseBuilder.build(); } } 

    Disadvantages:

    • The implementation detail of Request revealed

    • Reponse return Reponse is common

    • Missing return type grammar in WADL

    • client proxy with unnecessary Request parameter

  • Request as an instance variable

    Interface:

     @Path("myentity") public interface MyEntityResource @GET @Produces(MediaType.APPLICATION_JSON) public Response getMyEntity(); } 

    Implementation:

     public class MyEntityResourceImpl implements MyEntityResource @Context private Request request @Override public Response getMyEntity() { final MyEntity myEntity = ... // load entity final String eTagValue = ... // calclutate value of ETag final EntityTag eTag = new EntityTag(eTagValue); ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag); if (responseBuilder == null) { return Response.ok(user).tag(eTag).build(); } return responseBuilder.build(); } } 

    Disadvantages:

  • ShallowEtagHeaderFilter as a web filter

    web.xml:

     <filter> <filter-name>etagFilter</filter-name> <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class> </filter> <filter-mapping> <filter-name>etagFilter</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping> 

    Interface:

     @Path("myentity") public interface MyEntityResource @GET @Produces(MediaType.APPLICATION_JSON) public MyEntity getMyEntity(); } 

    Implementation:

     public class MyEntityResourceImpl implements MyEntityResource @Override public MyEntity getMyEntity() { final MyEntity myEntity = ... // load entity return myEntity; } } 

    Disadvantages:

    • Poor server performance, see JavaDoc

    • only works with uncommitted response

    • support weak ETag

  • Custom WriterInterceptor as a JAX-RS Interceptor

    interceptor:

     public class CustomInterceptor implements WriterInterceptor { @Context private Request request; @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { OutputStream old = context.getOutputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try { context.setOutputStream(buffer); context.proceed(); byte[] entity = buffer.toByteArray(); String etag = ... // calclutate value of ETag context.getHeaders().putSingle(HttpHeaders.ETAG, etag); ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag); if (responseBuilder == null) { throw new WebApplicationException(responseBuilder.status(Response.Status.NOT_MODIFIED).header(HttpHeaders.ETAG, etag).build()); } old.write(entity); } finally { context.setOutputStream(old); } } } 

    See also: ServerCacheInterceptor (Resteasy)

    Interface:

     @Path("myentity") public interface MyEntityResource @GET @Produces(MediaType.APPLICATION_JSON) public MyEntity getMyEntity(); } 

    Implementation:

     public class MyEntityResourceImpl implements MyEntityResource @Override public MyEntity getMyEntity() { final MyEntity myEntity = ... // load entity return myEntity; } } 

    Disadvantages:

    • There is no predefined interceptor for jersey.

    • Poor server performance

    • support weak ETag

    • Ugly workaround with WebApplicationException

+5
source

You can use any caching mechanism applicable for standard java along with jersey, for example Ehcache .

You only need to pay attention to make sure that your data in the backend has not changed.

Here is a simple example with Ehcache :

 @GET @Path("{id}") public List<Data> getData(@PathParam("id") Long id) { Element element = CacheManager.getInstance().getCache("test").get(id); if(element == null) { Data value = fetchElementFromBackend(id); CacheManager.getInstance().getCache("test").put(new Element(id, value)); return value; } return element.getObjectValue(); } 
+3
source

All Articles