I have a single-instance class, implementing ExceptionMapper. It's not a static class, but it's a class for which I know only single instance is created (I checked - constructor is called only once).
My class uses @Context HttpServletRequest, and I can clearly observe that when my ExceptionMapper.toResponse() method is called, the @Context 'request' parameter has a value which is relevant for a request where the exception is thrown.
The doc says this is indeed by-design supported feature and that it's done by using "proxies".
I wonder how exactly this is implemented - how a single instance can have different member variable values simultaneously?
Thank you,
AG
P.S.: here's the test code:
@Provider
public class MyExceptionMapper implements ExceptionMapper<Exception> {
public MyExceptionMapper() {
System.out.println("CTOR!!");
}
@Context HttpServletRequest req;
public static boolean done = false;
public Response toResponse(Exception ex) {
if (!done) {
done = true;
Thread.sleep(10000);
}
System.out.println(req.getRequestURI());
return null;
}
}
My REST handler method throws exception, so when I execute the following 2 requests "in parallel" (the sleep above makes sure first one is not finished when second one arrives and IMHO should modify the one-and-only 'req' field):
- http://localhost/app/one
- http://localhost/app/two
my program prints:
CTOR!
http://localhost/app/one
http://localhost/app/two
The simplest method of achieving the effect you observe is for the injected HttpServletRequest
object to actually be a proxy object, a thread-aware delegate for the real HttpServletRequest
. When you call methods on the delegate, all they do is look up the correct real object (e.g., via a thread local variable) and pass the call onto that. This strategy is relatively simple to get right, and as it is an interface we definitely don't have to worry about field accesses (which are quite a bit trickier to proxy for).
There's a few different ways to construct such a proxy object. In particular, it could be done by directly implementing the HttpServletRequest
interface, or it could be done more generically via the Java general dynamic proxy mechanism (which can construct a proxy for any interface). There are other more elaborate possibilities such as runtime code generation, but they're unnecessary here. OTOH, I wouldn't be at all surprised if HttpServletRequest
was directly implemented; it's a somewhat important class for a JAX-RS implementation…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With