users@javaee-spec.java.net

[javaee-spec users] [jsr366-experts] Re: Compatibility Problems with MR Resource Annotation Widening

From: Jason Greene <jason.greene_at_redhat.com>
Date: Thu, 26 Feb 2015 21:02:38 -0600

>
> On Feb 26, 2015, at 4:19 PM, Bill Shannon <bill.shannon_at_oracle.com> wrote:
>
> Jason Greene wrote on 02/26/2015 11:06 AM:
>> With CDI, @Resource (and the other EE injection bindings it supports) do not
>> create JNDI bindings. They just act as a lookup mechanism to bridge the EE
>> resource model with the CDI model.
>
> Um, ya, that's not what the spec says. You need to be able to override
> these injection points just like any others. If you don't create JNDI
> entries for them, there's no way to refer to them in the deployment
> descriptors.

So my recollection, was that this was intentional since the bindings arenít useful to CDI applications, and you could always reference another binding defined by a component which did support it, if you needed such behavior. The deployment descriptor for CDI doesnít allow you to override these bindings, and the other deployment descriptor locations donít cover the full set where @Resource can appear (for example ejb-jar overrides are defined on ejb components and not globally). Finally, @Resource (and the other EE bindings) can only appear on producer fields, which is a subset of what 250 defined.

Iíll ping Pete to see if he remembers the same, but yeah I agree the combination of the specs implies that it should work, other than the fact that it canít work the way the global rules are defined.

>
>>> Injection of Java EE resources should be the same whether it's being done
>>> by Weld or something else.
>>
>> So we could make it consistent, but we would need to define the namespace
>> rules for it. Otherwise, it would lead to failures in CDI since they can
>> occur on any class and those classes donít have component namespaces (the CDI
>> spec and tutorials and so on do not set the name attribute on @Resource).
>
> Right, that's what we're trying to clarify here. These injection points on
> non-component classes need to use java:module or higher, depending on where
> they're packaged.

Yeah I think itís a good idea to address it just like that.

>
> Some of this wasn't as clearly spelled out in the spec as we would like.
> You could only figure it out by connecting the dots of several separate
> requirements. That's why we're trying to clarify the spec by connecting
> the dots explicitly.
>
>>>>> It seems that we have to handle at least some cases of superclasses
>>>>> defining resources in the same namespace as the subclass. Sadly, you
>>>>> may be right that we have to handle that even in the case where the
>>>>> superclass is in a library
>>>>>
>>>>> Let's look at the general algorithm for initializing the JNDI
>>>>> namespaces. (We'll ignore deployment descriptor overriding for now.
>>>>> We'll also ignore application clients for now.)
>>>>
>>>> Iíll answer your question below first, by describing, very coarsely, how
>>>> our processing works. Our processing is component centric. We have a
>>>> first pass class structure and annotation scan which reads all the
>>>> bytecode in a deployment, including all possible places in the deployment
>>>> classes can exist, and constructs a set of shared indexes. We also do
>>>> something similar wit XML metadata, although each EE component layer has
>>>> to register the relevant parsing logic. From that information we have a
>>>> number of fine grained deployment processors (you can relate it to
>>>> something like an interceptor), installed by the various EE layers, which
>>>> all collaborate to create a set of component definitions. Those component
>>>> definitions are assembled with all of the JNDI binding information thats
>>>> relevant to the component.
>>>>
>>>> So in other words we notice every place that @Resource occurs, we just
>>>> donít do anything with that data until we process the component, and
>>>> processing the component involves analyzing the resource data for all
>>>> classes that make up the component.
>>>
>>> And how does that work for CDI managed beans? That's the case that
>>> motivated us to process annotations on all classes, not just some limited
>>> set of well defined easily discovered component classes.
>>
>> We pass the annotation indexes to CDI, register a callback which is triggered
>> on bootstrap, and that callback does a JNDI lookup. I donít think its
>> possible to analyze without bootstrapping CDI since portable extensions can
>> dynamically create annotations.
>
> Exactly my point.
>
> These annotations need to be processed at deployment time in order to work
> properly. If you wait until CDI is bootstrapped, it's too late.
> So you need
> to process these annotations on all classes, whether CID is using them or not,
> so that they'll work properly.

Why? I donít see how this is required. The CDI RI bootstrap is broken into separate phases, and that allows you to analyze all this stuff, and do it cooperatively/in-parallel before user code is ever executed, and certainly at deployment time. Now maybe the EE RI needs something else out of the CDI RI SPI, but thats really just an implementation issue.

The one exception is portable extensions, as those are a container SPI contract, and participate during deployment and undeployment.

>
> These classes need to be able to contain resource *definitions*, not just
> references. And as I said above, they need to define resource references
> that can be overridden in the deployment descriptor.
>
> (As far as I know, there's no way for a CDI extension to dynamically
> add (e.g.) an @Resource annotation to a class. And again, since the
> information from those annotations needs to be visible at deployment
> time, that's not going to work.)

A portable extension can emit any injection point, including a resource injection point and the generic callback should still work since the container wouldnít know the difference (unless it looked at the bytecode itself).

This looks like it should work on the EE RI (I havenít tried it though):

https://java.net/projects/glassfish/sources/svn/content/trunk/main/appserver/web/weld-integration/src/main/java/org/glassfish/weld/services/InjectionServicesImpl.java?rev=63779

-snip-

> Before CDI, the set of classes was quite restricted. These were the
> "container managed" classes. These were the classes instantiated by the
> container, not by the application, which gave the container the opportunity
> to perform injection. Clearly many people would like injection to occur
> for "new", but that's not going to happen, so we described which classes
> the container was managing, and thus which classes we could actually make
> injection work on.
>
> After CDI, we expanded the set to include all the container managed classes
> that CDI managed, which meant almost anything that could be used as a CDI
> bean. The only way to make injection work in all those cases is to consider
> every class a potential container managed class and to process these resource
> reference and definition annotations on all these classes. That's why
> Chapter 8 says you have to collect this deployment information (and again,
> resource reference and definition annotations are just another way of
> specifying deployment information) from all classes at deployment time.
>
> I don't know how else to make the requirements of the spec actually work
> correctly, which is why we viewed this as a clarification, not a change.

If its just a matter of saying all of these types have to be looked at, then I think we have already defined that, since all of the relevant specs specify which types are eligible. If, however, theres a new set of classes that are receiving injection & bindings, then thatís by definition a scope expansion.

>
> Note that this is different than how @Inject is handled. @Inject doesn't
> convey any deployment information. All processing of @Inject is done after
> deployment succeeds. This is one of the issues we had with potentially
> allowing use of @Inject to directly refer to Java EE resources. Without
> knowledge of these references available at deployment time, the information
> required to map these references to actual resources was missing, as was
> any ability to override those references.

You mean for some 330 implementations right? With CDI all injection points are calculated and validated at deployment time (with portable extensions as the only user defined participants, but they have a very specific role, which is modifying metadata). The only bit with @Inject that happens at runtime is injection when objects are physically instantiated, but thats exactly the same as the traditional EE @Resource.