You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomee.apache.org by Antoine Reilles <ar...@gmail.com> on 2013/04/07 23:32:04 UTC

Issue with @Context injection in CDI beans

Hi,

I'm running into issues when defining a RequestScoped CDI bean to be
injected in a jax-rs service, and initialized with information from the
http request.
My first problem is that the @Context HttpServletRequest that gets injected
in the CDI bean is invalid (the threadlocal proxy points to null, thus
raising NPE when a method is called on the object) whenever the same
@Context HttpServletRequest is not injected in the jax-rs context. If the
servletrequest in injected in the jax-rs endpoint, then it is properly
available from the CDI bean.
The second issue I have is that injecting the HttpServletResponse in the
CDI bean makes it available with the same limitations as the
HttpServletRequest, but it is no more available (again, a thread local
proxy pointing to null) in the @PreDestroy method of the CDI bean.

Here are samples of what I used to test, I can provide a complete sample if
it is useful.

The service is simply:
@Path("service")
@Produces(MediaType.TEXT_PLAIN)
public class Service {
  @Context HttpServletRequest request;
  @Context HttpServletResponse response;
  @Inject Ctx ctx;

  @GET
  public String foo() {
    return "foo: "+ctx;
  }
}

with the two @Context annotated fields triggering different behavior in the
CDI bean when commented out.
The CDI bean itself is:
@RequestScoped
public class Ctx {

  @Context HttpServletRequest request;
  @Context HttpServletResponse response;
  private String requesturi;
  Ctx() {
    requesturi = null;
  }

  @PostConstruct
  public void postConstruct() {
    ServletRequest localreq =
((org.apache.openejb.rest.ThreadLocalHttpServletRequest)request).get();
    if (null == localreq) {
      System.out.println("null request injected");
    } else {
      requesturi = request.getRequestURI();
    }
    System.out.println("Ctx @PostConstruct:"+this);
    ServletResponse localResp =
((org.apache.openejb.rest.ThreadLocalHttpServletResponse)response).get();
    if (null == localResp) {
      System.out.println("null response injected");
    } else {
      System.out.println("Ctx @PostConstruct Response:
"+response.getStatus());
    }
  }

  @PreDestroy
  public void preDestroy() {
    System.out.println("Ctx @PreDestroy:"+this);
    ServletResponse localResp =
((org.apache.openejb.rest.ThreadLocalHttpServletResponse)response).get();
    if (null == localResp) {
      System.out.println("null response injected at preDestroy");
    } else {
      System.out.println("Ctx @PreDestroy Response: "+response.getStatus());
    }
  }
}

I had to resort to casts to ThreadLocalHttpServletRequest to test the
injected proxies, since calling any method on a proxy pointing null
triggers an NPE, to display traces.
When the two @Context annotated fields are present in the Service class, I
do get traces like this:
Ctx @PostConstruct:Ctx: service
Ctx @PostConstruct Response: 200
Ctx @PreDestroy:Ctx: service
null response injected at preDestroy

and when the two fields are commented out in the Service class, the traces
are:
null request injected
Ctx @PostConstruct:Ctx: null
null response injected
Ctx @PreDestroy:Ctx: null
null response injected at preDestroy


I tested this behavior with 1.5.1, 1.5.2 and todays 1.6.0 snapshot, and got
the very same behavior.

Any suggestions on how I could make this work ?

Best regards,
antoine

Re: Issue with @Context injection in CDI beans

Posted by "John D. Ament" <jo...@gmail.com>.
I believe the JAX-RS spec (which defines @Context) only defines the use of
@Context with JAX-RS objects.  It does not define how it should be injected
into CDI objects.

You have some options though.  There are open frameworks like Seam 3 and
DeltaSpike (and probably CODI offers this as well) which can allow you to
@Inject your HTTP Request in to your CDI beans.  You could also do it
yourself with a servlet listener and a producer method for the
request/response.


On Sun, Apr 7, 2013 at 5:32 PM, Antoine Reilles <ar...@gmail.com> wrote:

> Hi,
>
> I'm running into issues when defining a RequestScoped CDI bean to be
> injected in a jax-rs service, and initialized with information from the
> http request.
> My first problem is that the @Context HttpServletRequest that gets injected
> in the CDI bean is invalid (the threadlocal proxy points to null, thus
> raising NPE when a method is called on the object) whenever the same
> @Context HttpServletRequest is not injected in the jax-rs context. If the
> servletrequest in injected in the jax-rs endpoint, then it is properly
> available from the CDI bean.
> The second issue I have is that injecting the HttpServletResponse in the
> CDI bean makes it available with the same limitations as the
> HttpServletRequest, but it is no more available (again, a thread local
> proxy pointing to null) in the @PreDestroy method of the CDI bean.
>
> Here are samples of what I used to test, I can provide a complete sample if
> it is useful.
>
> The service is simply:
> @Path("service")
> @Produces(MediaType.TEXT_PLAIN)
> public class Service {
>   @Context HttpServletRequest request;
>   @Context HttpServletResponse response;
>   @Inject Ctx ctx;
>
>   @GET
>   public String foo() {
>     return "foo: "+ctx;
>   }
> }
>
> with the two @Context annotated fields triggering different behavior in the
> CDI bean when commented out.
> The CDI bean itself is:
> @RequestScoped
> public class Ctx {
>
>   @Context HttpServletRequest request;
>   @Context HttpServletResponse response;
>   private String requesturi;
>   Ctx() {
>     requesturi = null;
>   }
>
>   @PostConstruct
>   public void postConstruct() {
>     ServletRequest localreq =
> ((org.apache.openejb.rest.ThreadLocalHttpServletRequest)request).get();
>     if (null == localreq) {
>       System.out.println("null request injected");
>     } else {
>       requesturi = request.getRequestURI();
>     }
>     System.out.println("Ctx @PostConstruct:"+this);
>     ServletResponse localResp =
> ((org.apache.openejb.rest.ThreadLocalHttpServletResponse)response).get();
>     if (null == localResp) {
>       System.out.println("null response injected");
>     } else {
>       System.out.println("Ctx @PostConstruct Response:
> "+response.getStatus());
>     }
>   }
>
>   @PreDestroy
>   public void preDestroy() {
>     System.out.println("Ctx @PreDestroy:"+this);
>     ServletResponse localResp =
> ((org.apache.openejb.rest.ThreadLocalHttpServletResponse)response).get();
>     if (null == localResp) {
>       System.out.println("null response injected at preDestroy");
>     } else {
>       System.out.println("Ctx @PreDestroy Response:
> "+response.getStatus());
>     }
>   }
> }
>
> I had to resort to casts to ThreadLocalHttpServletRequest to test the
> injected proxies, since calling any method on a proxy pointing null
> triggers an NPE, to display traces.
> When the two @Context annotated fields are present in the Service class, I
> do get traces like this:
> Ctx @PostConstruct:Ctx: service
> Ctx @PostConstruct Response: 200
> Ctx @PreDestroy:Ctx: service
> null response injected at preDestroy
>
> and when the two fields are commented out in the Service class, the traces
> are:
> null request injected
> Ctx @PostConstruct:Ctx: null
> null response injected
> Ctx @PreDestroy:Ctx: null
> null response injected at preDestroy
>
>
> I tested this behavior with 1.5.1, 1.5.2 and todays 1.6.0 snapshot, and got
> the very same behavior.
>
> Any suggestions on how I could make this work ?
>
> Best regards,
> antoine
>