5

I've got a session scoped CDI bean, and I need to somehow access the HttpServletRequest object in this bean's @PostConstruct method. Is it possible? I've tried to Inject such an object, but it results in:

WELD-001408 Unsatisfied dependencies for type [HttpServletRequest] with qualifiers     [@Default] at injection point [[field] @Inject ...]

As I understood while googling, the Seam framework has such a functionality, but I have a standard Java EE application on a GlassFish server.

Is it even possible to somehow pass the request to a CDI bean's @PostConstruct method?

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
wojtek88
  • 299
  • 1
  • 3
  • 13
  • 1
    Looks like you want to access to request query string parameters, right? – Luiggi Mendoza Aug 12 '13 at 14:18
  • I want to access UserPrincipal – wojtek88 Aug 12 '13 at 14:23
  • possible duplicate of [Injection of HttpServletRequest](http://stackoverflow.com/questions/13419887/injection-of-httpservletrequest) – Luiggi Mendoza Aug 12 '13 at 14:33
  • I saw this topic already, but @Context annotation crashes passivation of my bean, and when I have this annotation I can't Inject my bean any longer (bean implements Serializable already). – wojtek88 Aug 12 '13 at 14:41
  • 1
    @Luiggi (and wojetk) I find that duplicate also very curious. The `@Context` annotation is only applicable inside a JAX-RS webservice class (like as that `@ManagedProperty` is only applicable inside a JSF managed bean class). However, *nothing* in the question indicates that the OP is using JAX-RS and *nothing* in the answer indicates that the `@Context` is limited to JAX-RS webservice. Yet the answer is accepted and OP confirmed that it works. It's either a big coincidence and a really good blind guess, or the OP is lying. – BalusC Aug 12 '13 at 16:48
  • I believe rdcrng has right solution for your question, if need other things from the HttpServletRequest, you'll need to create a producer. – LightGuard Aug 12 '13 at 18:02

2 Answers2

14

As per your comment, you want access to the user principal. You can just inject it like this: @Inject Principal principal; or @Resource Principal principal;, see Java EE 6 Tutorial.

Update

I'll answer your direct question. In Java EE 7 (CDI 1.1) injection of HttpServletRequest is supported out of the box. In Java EE 6 (CDI 1.0) however, this is not supported out of the box. To get it working, include the class below into your web-app:

import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {

    private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<>();

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        SERVLET_REQUESTS.set(sre.getServletRequest());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        SERVLET_REQUESTS.remove();
    }

    @Produces
    private ServletRequest obtain() {
        return SERVLET_REQUESTS.get();
    }

}

Note: Tested only on GlassFish 3.1.2.2

rdcrng
  • 3,415
  • 2
  • 18
  • 36
  • SCHWEET! this worked! I did however need to add my own Qualifier to the obatain() method and the injection point. But otherwise, spot on! – demaniak Apr 17 '14 at 13:49
  • I do not think that will handle passivating correctly in case it is injected into a `SessionScoped` bean, or any other bean with a passivating context? – YoYo Apr 15 '19 at 20:47
1

When using the code from rdcrng be aware of the following:
* The producer-method obtain is dependent-scoped, thus is only called once for application scoped beans (and will resolve to problems for every other request except the first)
* You can solve this with @RequestScoped
* When RequestScoped annotated, you will only get a proxy, and thus you cannot cas it to HttpServletRequest. So you maybe want a producer for HttpServletRequest.

Also note: As per CDI specification link passage 3.6, java ee beans are NOT consideres managed beans. Thus you will end up with two instances of CDIServletRequestProducingListener - one managed by the Java EE container, one managed by the CDI-container. It only works because SERVLET_REQUESTS is static.

Following the modified code for your convenience.

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {

private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<ServletRequest>();

@Override
public void requestInitialized(ServletRequestEvent sre) {
    SERVLET_REQUESTS.set(sre.getServletRequest());
}

@Override
public void requestDestroyed(ServletRequestEvent sre) {
    SERVLET_REQUESTS.remove();
}

@RequestScoped
@Produces
private HttpServletRequest obtainHttp() {
    ServletRequest servletRequest = SERVLET_REQUESTS.get();
    if (servletRequest instanceof HttpServletRequest) {
        return (HttpServletRequest) servletRequest;
    } else {
        throw new RuntimeException("There is no HttpServletRequest avaible for injection");
    }
}

}

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
markus_
  • 480
  • 3
  • 12