I have a Jersey 2 Web Service that upon receiving a request, makes another request to another web service in order to form the response for the original request. So, when client "A" makes a request to my web service "B", "B" makes a request to "C" as part of forming the response to "A".
A->B->C
I want to implement a filter for a Jersey 2 web service that essentially does this:
Client "A" will send a request that has a header like "My-Header:first"
When my web service "B" then makes a client request "C", it should append to that header, so it sends a request with this header "My-Header:first,second".
I want to implement this as a filter so all of my resources don't have to duplicate the logic of appending to the request header.
However, in Jersey 2, you get these 4 filters:
- ContainerRequestFilter - Filter/modify inbound requests
- ContainerResponseFilter - Filter/modify outbound responses
- ClientRequestFilter - Filter/modify outbound requests
- ClientResponseFilter - Filter/modify inbound responses
I need to use the header from an inbound request, modify it, then use it an outbound request, so essentially I need something that is both a ContainerRequestFilter and a ClientRequestFilter. I don't think implementing both in the same filter will work, as you don't know which Client Request maps to which Container Request, or do you?
I found a nice way to do this that doesn't use
ThreadLocal
to communicate between theContainerRequestFilter
and theClientRequestFilter
, as you can't assume that client requests made in response to a container request will be on the same thread.The way I achieved this is by setting a property in the
ContainerRequestConext
object in theContainerRequestFilter
. I can then pass theContainerRequestContext
object (either explicity or through dependency injection) into myClientRequestFilter
. If you use dependency injection (if you're using Jersey 2 then you are probably using HK2), then all of this can be achieved without modifying any of your resource level logic.Have a
ContainerRequestFilter
like this:And a
ClientRequestFilter
that takes aContainerRequestContext
in its constructor:Then it's just a case of tying this all together. You will need a factory to create any
Client
orWebTarget
that you need:Then register the filter and bind your factory on your main application
ResourceConfig
:A container filter can implement both,
ContainerRequestFilter
andContainerResponseFilter
in one single class. The same is true for client filters,ClientRequestFilter
andClientResponseFilter
can both be implemented in one single filter implementation.But you cannot mix as far as I know. Instead, you can have two separate filters that communicate with each other e.g. using
ThreadLocal
pattern: