jsr366-experts@javaee-spec.java.net

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

From: Bill Shannon <bill.shannon_at_oracle.com>
Date: Thu, 26 Feb 2015 14:19:38 -0800

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.

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

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.

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

>> The whole model of resource references in Java EE was that you could
>> ensure at deployment time that everything the application needed was
>> available, so that you didn't have failures at runtime. It's a very static
>> model of resources, which clearly has advantages and disadvantages, but
>> this has always been the model.
>
> So even though CDI made things a little more dynamic, all of the dynamic bits
> happen eagerly, so the callback for every EE injection point happens during
> bootstrap before the application code is actually running, so it should be
> possible to validate and/or alter the lookup values if needed.

Yes. It needs to happen at deployment time.

>> Our goal has always been to detect these errors as soon as possible,
>> usually at deployment time. It's impossible to know whether these errors
>> will cause the application to fail or will be harmless.
>
> I guess it depends on how you view it. My mental model has always been that
> EE annotation metadata is just a bunch of configuration snippets (each of
> which are neither valid nor invalid) that ultimately gets assembled and
> merged into the real and final configuration, and that’s the piece that gets
> validated.

Yes, at deployment time.

The annotations are just a different way of specifying the same information
you can specify in a deployment descriptor, and that must be processed at
deployment time.

>> We never intended that JSR-250 annotations could be used in a Java EE
>> application for something other than what Java EE defines.
>
> I wasn’t a participant back then, so you know better than me. All I can say
> is that I don’t think framework developers got that message though. Since the
> spec is called “common annotations”, and it was included in Java SE, it sends
> a completely different message. To use an example, Spring overloads these,
> and making this sort of change in an MR would cause Spring deployments to
> start failing when they worked just fine on all previous versions.
>
> To be clear though, I’m not arguing we should let third-party frameworks
> dictate the EE spec (that would be a bit silly). My concern is breaking stuff
> in a maintenance release, and that causes users using these frameworks to
> seek other solutions.

The "standalone" specification for these "common annotations" is fairly
weak. The intent was that this would allow the annotations to be used
in other specifications that would more fully define the semantics of
these annotations. Java EE is such a specification.

Spring can use these annotations per the standalone specification, but
in the context of Java EE the behavior of these annotations is as specified
by Java EE. It's never been our intent to allow Spring to redefine the
semantics of these annotations or any other part of Java EE when running
in a Java EE product. If Spring wants to define a competing platform using
these annotations with their own semantics, that's up to them.

>> That's different than JSR-330 annotations, which we knew were being used
>> outside of CDI, and we wanted to allow products to support applications
>> with those annotations but without CDI interpreting those annotations.
>>
>> If a Java EE product isn't always processing JSR-250 annotations as
>> required by the Java EE spec, it's not compatible with the spec.
>>
>>> One thing I wonder though, is does this really bring enough value to
>>> justify the cost of the change? For example, it takes just one extra
>>> annotation to make a class a component (e.g.
>>> ManagedBean/Singleton/ApplicationScoped etc).
>>
>> I'm not sure what change you're referring to.
>>
>> We haven't been trying to *change* anything, only to clarify what we
>> originally intended. Admittedly our first attempt wasn't quite right, but
>> I'm hoping we're converging on agreement of the original intent.
>
> We previously had a restricted set of classes which had injection performed
> on them (EE components), and AFAICT, both algorithms expand it to cover all
> classes. This is effectively introducing a new kind of quasi EE-component.

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.

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.