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#...
> 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
>>>
>>