jersey icon indicating copy to clipboard operation
jersey copied to clipboard

ServletContext is invalid in MessageBodyWriter if handling async CompletionStage

Open rickardoberg opened this issue 1 year ago • 3 comments

My resources return CompletionStage<MyType> and then I have a MessageBodyWriter for MyType. The issue is that if the CompletionStage is not immediately complete upon returning from resource method then the MessageBodyWriter fails because the ServletContext accessed from HttpServletRequest has already been invalidated and set to null (by Jetty 11).

Is there a way around this so that the HttpServletRequest (injected with Provider<HttpServletRequest> in MessageBodyWriter constructor and accessed in the writeTo method) becomes valid again? Or is this just a bug that needs to be fixed in Jersey?

rickardoberg avatar Feb 06 '24 05:02 rickardoberg

The MessageBodyWriter is a singleton, it is not recreated for each request. Whatever injected, it would not be aligned with the current request.

Possibly, you can try to inject InjectionManager class and try to call injectionManager.getInstance(HttpServletRequest.class) in the writeTo method.

The lifecycle of HttpServletRequest class is handled by the Servlet container, i.e. by Jetty. If Jetty invalidates, Jersey cannot prevent that.

jansupol avatar Feb 06 '24 07:02 jansupol

I'm injecting Provider<HttpServletRequest>into the MessageBodyWriter constructor, which in writeTo returns a proxy to the correct object. This part is fine. The issue is that because of the asynchronous nature of returning a CompletionStage<MyType> from the resource the request has not been reassociated correctly with the servletcontext. There's some scope fixing (or similar) that needs to happen before calling writeTo, when the result is a CompletionStage. The main issue is that HttpServletRequest.getServletContext needs to return the correct value.

rickardoberg avatar Feb 06 '24 07:02 rickardoberg

There are two possibilities:

  • The injected HttpServletRequest provided does not belong to the current request
  • Jetty ended the current request and set the HttpServletRequest.getServletContext to return null.

You might be trying to provide request-scoped information outside of a request. The JAX-RS way which avoids the injection is to utilize WriterInterceptor.getProperty during the entity writing and setting up the property in the resource class or in the ContainerFilter where the request-scoped information is available.

jansupol avatar Feb 06 '24 13:02 jansupol