This is a quick post which points out how to share contextual user-defined (custom) data between JAX-RS filters
Filter execution
- It is chain based: one filter gets executed after another
- Request filters are executed before Response filters
- If a filter throws an exception, the chain breaks and other filters are skipped i.e. an exception from a Request filter will auto-abort all other Request filters. The same is applicable to Response filters
For more info, please do check out one of my existing blog posts which discussed JAX-RS server side processing pipeline in depth
Sharing data b/w filters
JAX-RS API enables sharing of user-defined data amongst filters associated with a particular request
- It is abstracted in the form of a Map<String,Object> (pretty natural choice) via the ContainerRequestContext interface
- Get all the custom properties using the getPropertyNames() method
- The value of a specific property can be fetched (from the Map) using getProperty(String name)
- Overwrite an existing property or a add a new one using setProperty(String name, Object val)
Examples
Here is how multiple Request filters can share user-defined contextual data amongst themselves
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ReqFilter_1 implements ContainerRequestFilter { | |
@Override | |
public void filter(ContainerRequestContext cReqCtx) throws IOException { | |
cReqCtx.setProperty("prop1", "value1"); | |
} | |
} | |
public class ReqFilter_2 implements ContainerRequestFilter { | |
@Override | |
public void filter(ContainerRequestContext cReqCtx) throws IOException { | |
String val1 = (String) cReqCtx.getProperty("prop1"); | |
cReqCtx.setProperty("prop1", "value1"); | |
cReqCtx.setProperty("prop2", "value2"); | |
} | |
} | |
public class ReqFilter_3 implements ContainerRequestFilter { | |
@Override | |
public void filter(ContainerRequestContext cReqCtx) throws IOException { | |
String val1 = (String) cReqCtx.getProperty("prop1"); | |
String val2 = (String) cReqCtx.getProperty("prop2"); | |
Collection<String> customProperties = cReqCtx.getPropertyNames(); | |
} | |
} |
Another example where a Response filter uses the contextual data set by a Request filter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Priority(Priorities.AUTHENTICATION) | |
public class ReqFilter_1 implements ContainerRequestFilter { | |
@Override | |
public void filter(ContainerRequestContext cReqCtx) throws IOException { | |
cReqCtx.setProperty("random-token", "token-007"); //generated and used internally | |
} | |
} | |
public class ResponseFilter implements ContainerResponseFilter { | |
@Override | |
public void filter(ContainerRequestContext cReqCtx, ContainerResponseContext cRespCtx) throws IOException { | |
String responseToken = (String) cReqCtx.getProperty("random-token"); //get the property | |
if(responseToken!=null){ | |
cRespCtx.getHeaders.put("random-token-header" , responseToken); //set it to HTTP response header | |
} | |
} | |
} |
To be noted…
The same capability is available in the Client side JAX-RS filters as well. The only difference is that you would be interacting with an instance of the ClientRequestContext
Further reading
- For more discussion on Filters and other JAX-RS 2.0 stuff you can peek into this article in the latest Java Magazine edition
- I had discussed different binding strategies for JAX-RS filters in my previous post
- Check out the JAX-RS 2.0 specification doc
Cheers !
HI Abhishek, thanks for the article. You have written 3 filter classes and in 2 of them you set some value and in 3rd one you get some value. You have also mentioned that filters are also working in a chain but i am unable to understand that how does JAX-RS know which filter to be executed first. You can have chaining start from any filter. But in your example, it should started from 1, 2 and 3. Could you plz explain?
LikeLike
Tushar – one can specify the ordering by using the @Priority filter
LikeLike
Pingback: JSON Web Token in action with JAX-RS | Thinking in Java EE (at least trying to!)
Pingback: JSON Web Token in Action with JAX-RS | Voxxed