Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey 2: filters and @Context injections

Tags:

jersey-2.0

I've the following question:

ContainerRequestFilter is a singleton, but reading this:

Jaxrs-2_0 Oracle Spec

in chapter 9.2, they say:

Context is specific to a particular request but instances of certain JAX-RS components (providers and resource classes with a lifecycle other than per-request) may need to support multiple concurrent requests. When injecting an instance of one of the types listed in Section 9.2, the instance supplied MUST be capable of selecting the correct context for a particular request. Use of a thread-local proxy is a common way to achieve this.

In the chapter 9.2, the HttpServletRequest is not mentioned.

So the question is: is it safe in terms of concurrency to inject the HttpServletRequest inside a custom ContainRequestFilter?

I mean this:

@Provider
@PreMatching
public class AuthenticationFilter implements ContainerRequestFilter {

   @Context private HttpServletRequest request;  

   @Override
   public void filter(ContainerRequestContext requestContext) throws IOException {
    // This is safe because every thread call the method with its requestContext
    String path = requestContext.getUriInfo().getPath(true);

    // Is this safe? The property request is injected by using @Context annotation (see above)
    String toReturn = (String)request.getAttribute(name);

    [...]
}

I did some empirical tests on my IDE in debug mode, sending with two different browsers two different and concurrent requests and it seems to work well; I noticed that the filter's instance is ever the same (it's a singleton), but the injected HttpServletRequest is different in the two cases.

I readed even this thread: How to access wicket session from Jersey-2 request filter? and it seems that my tests are confirmed.

But I still have doubts.

Confirm?

like image 677
Rick Deckard Avatar asked Nov 10 '15 14:11

Rick Deckard


1 Answers

Yes it's safe. To understand the problem, you should understand how scopes work. In any framework that deals with scopes (and injection), the feature is implemented similarly. If an object is in a singleton scope and another object in a lesser scope needs to be injected, usually a proxy of the object will be injected instead. When a call is made on the object, it's actually a call on the proxy.

Though the spec may not mention the HttpServletRequest specifically, most JAX-RS implementation have support for this. With Jersey in particular, if this was not possible (meaning the object is not proxiable), then you would get an error message on startup with something like "not within a request scope". The reason is that the ContainerRequestFilter is created on app startup, and all the injections are handled at that time also. If the HttpServletRequest was not proxiable, it would fail to inject because on startup, there is no request scope context.

To confirm that it is not the actual HttpServletRequest and is a proxy, you can log the request.getClass(), and you will see that it is indeed a proxy.

If you are unfamiliar with this pattern, you can see this answer for an idea of how it works.

See Also:

  • Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey
like image 198
Paul Samsotha Avatar answered Oct 02 '22 14:10

Paul Samsotha