Simplifying JAX-RS caching with CDI

This post explains (via a simple example) how you can use CDI Producers to make it a little easier to leverage cache control semantics in your RESTful services

The Cache-Control header was added in HTTP 1.1 as a much needed improvement over the Expires header available in HTTP 1.0. RESTful web services can make use of this header in order to scale their applications and make them more efficient e.g. if you can cache a response of a previous request, then you obviously need not make the same request to the server again if you are certain of the fact that your cached data is not stale!

How does JAX-RS help ?

JAX-RS has had support for the Cache-Control header since its initial (1.0) version. The CacheControl class represents the real world Cache-Control HTTP header and provides the ability to configure the header via simple setter methods. More on the CacheControl class in the JAX-RS 2.0 javadocs



So how to I use the CacheControl class?

Just return a Response object around which you can wrap an instance of the CacheControl class.

public class RESTfulResource {
public Response find(){
CacheControl cc = new CacheControl();
return Response.ok(UUID.randomUUID().toString()).cacheControl(cc).build();

Although this is relatively convenient for a single method, repeatedly creating and returning CacheControl objects can get irritating for multiple methods

CDI Producers to the rescue!

CDI Producers can help inject instances of classes which are not technically beans (as per the strict definition) or for classes over which you do not have control as far as decorating them with scopes and qualifiers are concerned.

The idea is to

  • Have a custom annotation (@CacheControlConfig) to define default values for Cache-Control header and allow for flexibility in case you want to override it

public @interface CachControlConfig {
public boolean isPrivate() default true;
public boolean noCache() default false;
public boolean noStore() default false;
public boolean noTransform() default true;
public boolean mustRevalidate() default true;
public boolean proxyRevalidate() default false;
public int maxAge() default 0;
public int sMaxAge() default 0;

  • Just use a CDI Producer to create an instance of the CacheControl class by using the InjectionPoint object (injected with pleasure by CDI !) depending upon the annotation parameters

public class CacheControlFactory {
public CacheControl get(InjectionPoint ip) {
CachControlConfig ccConfig = ip.getAnnotated().getAnnotation(CachControlConfig.class);
CacheControl cc = null;
if (ccConfig != null) {
cc = new CacheControl();
return cc;

  • Just inject the CacheControl instance in your REST resource class and use it in your methods

public class RESTfulResource {
@CachControlConfig(maxAge = 20)
CacheControl cc;
public Response find() {
return Response.ok(UUID.randomUUID().toString()).cacheControl(cc).build();

Additional thoughts

  • In this case, the scope of the produced CacheControl instance is @Dependent i.e. it will live and die with the class which has injected it. In this case, the JAX-RS resource itself is RequestScoped (by default) since the JAX-RS container creates a new instance for each client request, hence a new instance of the injected CacheControl instance will be created along with each HTTP request
  • You can also introduce CDI qualifiers to further narrow the scopes and account for corner cases
  • You might think that the same can be achieved using a JAX-RS filter. That is correct. But you would need to set the Cache-Control header manually (within a mutable MultivaluedMap) and the logic will not be flexible enough to account for different Cache-Control configurations for different scenarios

Results of the experiment

Use NetBeans IDE to play with this example (recommended)


  • A GET Request to the same URL will not result in an invocation of your server side REST service. The browser will return the cached value.


Although the code is simple, if you are feeling lazy, you can grab the (maven) project from here and play around

Have fun!


About Abhishek

Loves Go, NoSQL DBs and messaging systems
This entry was posted in Java, Java EE and tagged , , , , , , . Bookmark the permalink.

4 Responses to Simplifying JAX-RS caching with CDI

  1. Hi, nice example.

    Here we use RestEasy pre processor for that so just the annotation (at resource or method level) is enough:

    the problem, as far as I know, is that there is no equivalent feature in JaxRS specification so its vendor specific.


    • Abhishek says:

      Hi Rafael,

      Glad you liked the content ! 🙂

      I did go through the link you posted. But the problem statement (intercepting request methods with a parameter having a particular annotation) can be achieved in a standard way in JAX-RS 2.0 (Java EE 7), with the help of an interface called DynamicFeature . This can essentially help you register standard JAX-RS Interceptors (again, new in 2.0) in a dynamic fashion at run time by choosing the properties of you resource classes/methods with the help of the ResourceInfo interface

      Checked out your blog. Cool stuff! Following your content now 🙂



  2. Pingback: Efficient JAX-RS: Conditional GETs & PUTs | Thinking in Java EE (at least trying to!)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s