[weld-dev] @Resource annotation handling by Weld vs Servlet container

Jozef Hartinger jharting at redhat.com
Tue Apr 14 09:17:49 EDT 2015



On 04/14/2015 12:41 AM, Jan Bartel wrote:
> Jozef,
>
>
>
>>> Looking at the WeldServletLifecyle class on line 124, it will always
>>> provide an implementation of the ResourceInjectionServices (an
>>> instance of ServletResourceInjectionServices). If we were to provide
>>> our own implementation of ResourceInjectionServices, how would we
>>> override that one? Is there a way to get a hold of the Deployment and
>>> thus the BeanDeploymentArchives so we could set our own implementation
>>> up? Ideally we'd like a pure CDI api way of interacting with weld, but
>>> maybe that's not possible in this case?
>> You need to interact with Weld APIs to do this. A service can be overridden
>> using ServiceLoader mechanism. See
>> http://docs.jboss.org/weld/reference/2.2.10.Final/en-US/html/ri-spi.html#_registering_services
>> for details.
> Ok, great, I'll give this a go and report back.
Actually, this only work for global per-deployment Services. 
ResourceInjectionServices is a per-module type of service (in order to 
support EARs) and therefore this mechanism will not work. Sorry for 
misleading information. There isn't currently any nice way of overriding 
ResourceInjectionServices in weld-servlet.
>
>
>>> Alternatively, instead of Weld
>>>> hooking into lifecycle of Jetty-managed components, Jetty could use CDI
>>>> APIs
>>>> to perform CDI injection on instances it manages.
>>>>
>>> Yes, potentially we could do that, although we'd probably need your
>>> guidance on the best way to do that. Can  @Resource be  used by pojo
>>> beans or only by servlet artifacts (servlet/filter/listeners)? If the
>>> latter, then I'm fine for Jetty to do all the handling of @Resource.
>>> If not, then it probably makes sense for weld to handle it, and we'd
>>> need a way to disable Jetty's implementation if weld is present in a
>>> webapp ...
>> I think the best approach would be to modify the integrating decorator to
>> only provide CDI injection to Jetty-managed instances. I have implemented it
>> here:
>> https://github.com/weld/core/commit/f7420e34355c5c82ef516713c65fc6cd750fb651
> So if jetty is handling @Resource (handling making the jndi entries
> and injecting the fields/methods) for servlets/filters/listeners, what
> will happen if someone declares this in eg a servlet:
>
> public class  MyServlet extends HttpServlet
> {
>
>      @Producer @Resource (name="foo")
>      @MyDb
>      private DataSource db;
> }
>
> Will weld still inspect this class and find the producer and make it
> available for injection in other code?
Servlets, filters, etc. are considered to be non-contextual instances. 
That means their lifecycle is not managed by CDI and therefore they 
should not declare producer fields/methods, observer methods, etc.

In this particular case it is likely to work because the class of the 
servlet also happens to fulfill CDI managed bean requirements and 
therefore the class ends up being a source of two components - a Servlet 
and a CDI managed bean. The CDI managed bean will therefore handle the 
producer field access. Note however that the instances will be separate 
- i.e. CDI will create its own instance of the servlet class and will 
not use the one managed by the Servlet container. This last part are 
ugly internals and corner-cases of the two specs. The simplified point 
would be to not use @Produces on these non-contextual components at all.
>
> cheers
> Jan
>
>>> cheers
>>> Jan
>>>
>>>> Additional comments inline:
>>>>
>>>>
>>>> On 04/10/2015 02:00 AM, Jan Bartel wrote:
>>>>> Hi Weld developers,
>>>>>
>>>>> The Jetty project is looking at how we can do a tighter integration
>>>>> with Weld, also with a view to discussions in the Servlet Spec 4
>>>>> committee to alleviate the necessity for CDI implementations to
>>>>> maintain jetty-specific initialisation code.
>>>>>
>>>>> During investigations, I noticed that we seem to have a conflict in
>>>>> the handling of a few annotations for classes that are managed by the
>>>>> servlet container (ie servlets, filters, listeners etc):
>>>>>
>>>>> @Resource
>>>>> @PostConstruct
>>>>> @PreDestroy
>>>>>
>>>>> As Jetty puts a servlet/filter/listener into service, we introspect
>>>>> the class and find the above annotations and process them. It seems
>>>>> that Weld does too, as I see the following failure for this code
>>>>> snippet:
>>>>>
>>>>> public class TestListener implements ServletContextListener
>>>>> {
>>>>>        @Resource(mappedName="maxAmount")
>>>>>         private Double maxAmount;
>>>>> }
>>>>>
>>>>>
>>>>> javax.naming.NameNotFoundException; remaining name 'maxAmount'
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.jndi.local.localContextRoot.lookup(localContextRoot.java:429)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.jndi.local.localContextRoot.lookup(localContextRoot.java:533)
>>>>>        at javax.naming.InitialContext.lookup(InitialContext.java:411)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.spi.helpers.AbstractResourceServices.resolveResource(AbstractResourceServices.java:48)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.spi.helpers.AbstractResourceServices$1.createResource(AbstractResourceServices.java:121)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.AbstractResourceInjection.getResourceReference(AbstractResourceInjection.java:44)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.AbstractResourceInjection.injectResourceReference(AbstractResourceInjection.java:53)
>>>>>        at org.jboss.weld.util.Beans.injectEEFields(Beans.java:344)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.producer.ResourceInjector$1.proceed(ResourceInjector.java:69)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:48)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.producer.ResourceInjector.inject(ResourceInjector.java:72)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.injection.producer.BasicInjectionTarget.inject(BasicInjectionTarget.java:121)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.environment.servlet.inject.AbstractInjector.inject(AbstractInjector.java:55)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.environment.jetty.JettyWeldInjector.inject(JettyWeldInjector.java:15)
>>>>>        at
>>>>>
>>>>> org.jboss.weld.environment.jetty.WeldDecorator.decorate(WeldDecorator.java:105)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.util.DecoratedObjectFactory.decorate(DecoratedObjectFactory.java:77)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:335)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1349)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1342)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:743)
>>>>>        at
>>>>>
>>>>> org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:257)
>>>>>        at
>>>>> org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:505)
>>>>>
>>>>>
>>>>> Googling around, it is not clear to me exactly which of the Common
>>>>> Annotations (JSR250) that Weld supports and I'd appreciate some input
>>>>> from the Weld devs in order for Jetty to work out how best to move
>>>>> forward with Weld integration.
>>>>>
>>>>> In particular, I'd appreciate some clear feedback on which of the
>>>>> following @Resource annotation usages will be handled by Weld:
>>>>>
>>>>> @Resource on a class
>>>>> @Resource on a field
>>>>> @Resource on a method
>>>>> @Resource annotations without an accompanying @Producer annotation
>>>> @Resource on a field (with or without @Producer), @Resource on a method,
>>>> @PostConstruct and @PreDestroy are handled by Weld on a managed instance
>>>> (generally).
>>>>>
>>>>> Secondly, as can be seen from the stacktrace above, Weld is failing to
>>>>> find the matching JNDI entry for an @Resource annotation. This is
>>>>> because Weld appears not to be looking in "java:comp/env" namespace,
>>>>> although IIRC that is mandated by the JavaEE spec for EE managed
>>>>> classes (servlets/filters/listeners etc). So if Jetty delegates
>>>>> handling of some/all processing of @Resource, how do we ensure that
>>>>> Weld will be able to find the right JNDI entry?
>>>> This might be a bug in weld-servlet's ResourceInjectionServices
>>>> implementation. Can you file an issue at
>>>> https://issues.jboss.org/browse/WELD ?
>>>>
>>>>> thanks for your time,
>>>>> Jan
>>>>
>>>
>
>



More information about the weld-dev mailing list