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

Jan Bartel janb at webtide.com
Thu Jul 9 02:16:44 EDT 2015


Hi Josef,

The EE spec group were having a very long discussion about CDI and
annotation handling (thread ref:
https://java.net/projects/javaee-spec/lists/users/archive/2015-02/message/54)
wrt updating EE7 and creating EE8. Do you know where that landed? Is
there any clarification on whether the servlet container or CDI impl
is supposed to be interpreting the @Resource annotations?

cheers
Jan

On 14 April 2015 at 23:19, Jozef Hartinger <jharting at redhat.com> wrote:
>
>
> On 04/14/2015 07:17 AM, Jan Bartel wrote:
>>
>> Hi 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.
>>
>> I've implemented the service for the ResourceInjectionServices (for
>> now each method simply does a println), and it looks like weld is
>> seeing it:
>>
>> Apr 14, 2015 11:40:34 AM org.jboss.weld.bootstrap.AdditionalServiceLoader
>> put
>> DEBUG: Installing additional service
>> org.jboss.weld.injection.spi.ResourceInjectionServices (class
>> org.eclipse.jetty.cdi.servlet.ResourceInjectionServices)
>> Weld ResourceInjectionServices jetty constructor called
>>
>> However, it does not appear to be being used, as I see no output from
>> my service, but still get the following error:
>>
>> java.lang.RuntimeException: Error looking up maxAmount in JNDI
>>      at
>> org.jboss.weld.injection.spi.helpers.AbstractResourceServices.resolveResource(AbstractResourceServices.java:50)
>>      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)
>>
>> Any hints?
>
> Actually I somehow missed the fact the ResourceInjectionServices are
> per-module instead of per-deployment type of Service. As a result, it is not
> possible to override it using AdditionalServiceLoader. See my other e-mail
> for details. Sorry about that.
>
>>
>> thanks,
>> Jan
>>
>>>
>>>>> 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?
>>>
>>> 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
>>>>>>
>>>>>>
>>>>>
>>>
>>>
>>> --
>>> Jan Bartel <janb at intalio.com>
>>> www.webtide.com
>>> 'Expert Jetty/CometD developer,production,operations advice'
>>
>>
>>
>



-- 
Jan Bartel <janb at webtide.com>
www.webtide.com
'Expert assistance from the creators of Jetty and CometD'


More information about the weld-dev mailing list