Unable to inject ServletContext in ApplicationScoped bean
cvarona Jun 16, 2014 12:54 PMHi,
I have a ServletContextListener like this in my web application:
@WebListener public class Initialization implements ServletContextListener { @Inject @Any private Event<RtConf> _rtConfEvent; public void contextInitialized( ServletContextEvent sce ) { // rtConf retrieval from db, nothing worth mentioning RtConf rtConf = ... ; _rtConfEvent.fire( rtConf ); } ... }
I'm testing this in jetty 9.2 and Glassfish 4; _rtConfEvent won't get injected in jetty 9.1, even if the console output reads like this:
2014-06-16 18:02:09.739 INFO - jetty-9.1.0.v20131115
2014-06-16 18:02:10.909 INFO - Initialize Weld using ServletContainerInitializer
...
2014-06-16 18:02:11.051 INFO - WELD-000900: 2.2.1 (Final)
2014-06-16 18:02:11.203 INFO - WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
2014-06-16 18:02:11.260 WARN - WELD-001700: Interceptor annotation class javax.ejb.PostActivate not found, interception based on it is not enabled
2014-06-16 18:02:11.260 WARN - WELD-001700: Interceptor annotation class javax.ejb.PrePassivate not found, interception based on it is not enabled
2014-06-16 18:02:11.347 INFO - Jetty 7.2+ detected, CDI injection will be available in Listeners, Servlets and Filters.
These rt conf events are meant to make a certain configuration available to several application scoped components. In other words, I leverage the CDI event propagation mechanism in order to both create application wide components and transfer them the configuration. These components are beans like this:
@ApplicationScoped public class RtConfAwareImpl implements RtConfAware { @Inject private ServletContext _sctx; public static final Collection<ConfigAttribute> PERMIT_ALL = Collections.<ConfigAttribute>singletonList( new SecurityConfig( "permitAll" ) ); public static final Collection<ConfigAttribute> AUTHENTICATED = Collections.<ConfigAttribute>singletonList( new SecurityConfig( "authenticated" ) ); public void onRtConfActivation( @Observes RtConf pConf ) { // Do something with the provided conf and the injected servlet context } }
This servlet context injection fails:
18:30:46.987 [main] ERROR RT.COMP1 - WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:687) ~[weld-servlet-2.2.1.Final.jar:2014-05-09 12:21]
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:79) ~[weld-servlet-2.2.1.Final.jar:2014-05-09 12:21]
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:99) ~[weld-servlet-2.2.1.Final.jar:2014-05-09 12:21]
at org.jboss.weld.proxies.ServletContext$1191556859$Proxy$_$$_WeldClientProxy.getAttribute(Unknown Source) ~[weld-servlet-2.2.1.Final.jar:?]
By debugging I can see the event gets notified within a Request scope. I think that's quite surprising, for the RequestScoped annotation javadoc states that
The request scope is active:
- during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the container calls any ServletRequestListener or AsyncListener,
- during any Java EE web service invocation,
- during any remote method invocation of any EJB, during any asynchronous method invocation of any EJB, during any call to an EJB timeout method and during message delivery to any EJB message-driven bean, and
- during any message delivery to a MessageListener for a JMS topic or queue obtained from the Java EE component environment.
According to the JEE7 tutorial
Predefined beans are injected with dependent scope and the predefined default qualifier
@Default
Since the event is originating at a Listener and is targeting an ApplicationScoped bean I would expect the ServletContext to be smoothly injected. It isn't, and quite to my surprise I've found by debugging that Weld's ServletContextBean#getScope is defined like this:
@Override public Class<? extends Annotation> getScope() { return RequestScoped.class; }
which might or might not exert some influence on what's happening to me.
Am I doing something wrong? Is it ok to expect the injection works at that point? I've googled quite a bit and have been unable to find anybody attempting (and failing) to do something like this. Any help will be much appreciated.