repeating annotations comments
michael keith
michael.keith at oracle.com
Sat Dec 22 08:50:01 PST 2012
Okay. I'll give it a go and let you know.
-Mike
On 22/12/2012 1:03 AM, Joe Darcy wrote:
> Hi Mike,
> On 12/20/2012 7:48 PM, michael keith wrote:
>> Just to follow up on this, I did a quick survey and there are a
>> number of EE 6 specs that make use of the idiomatic container
>> pattern: EJB, JPA, JAXB, JAX-WS, JSF, Interceptors, Connectors, and
>> Common Annotations. These are just the EE 6 specs, I didn't go
>> through the ongoing EE 7 ones. This means that all of the
>> implementations, IDE's, 3rd party tools and frameworks that process
>> annotations from these specs will break, in many cases imperceptibly,
>> if the semantics of the existing reflection methods get changed. As I
>> mentioned earlier, while I was prepared to require that
>> implementations change once we upgraded the specs to use repeatable
>> annotations, I feel the fanout is too broad and the manner of
>> breakage too subtle that the cost of abandoning compatibility is too
>> high. If people feel there is confusion around the new methods acting
>> differently from the old ones in the presence of repeatable
>> annotations then perhaps we could go back to exploring the use of
>> different names for the new ones.
>
> It would be very helpful for someone to verify that the idiomatic
> container pattern used in the various EE specs can be successfully
> retrofitted to use the formal container pattern in the current JDK 8
> builds. Several adjustments were made to the initial formal container
> design to accommodate the actual usage patterns in EE.
>
> Thanks,
>
> -Joe
>
>>
>> -Mike
>>
>> On 17/12/2012 9:44 AM, Mike Keith wrote:
>>> Thanks for your comments, ideas and suggestions, Alex. I had more
>>> answers but my draft got prematurely sent. More stuff below.
>>>
>>> -Mike
>>>
>>> On 2012-12-16, at 10:33 PM, Mike Keith<michael.keith at oracle.com>
>>> wrote:
>>>
>>>> On 2012-12-14, at 8:41 PM, Alex Buckley<alex.buckley at oracle.com>
>>>> wrote:
>>>>
>>>>> Hi Mike,
>>>>>
>>>>> Thanks for the quick feedback. (I know you've been playing with
>>>>> the JDK8 b68 binary.)
>>>>>
>>>>> On 12/14/2012 1:59 PM, michael keith wrote:
>>>>>> 1. The getAnnotation(Class<T>) method is being changed to look
>>>>>> through
>>>>>> container annotations. This method returns an Annotation, i.e. a
>>>>>> single
>>>>>> instance, so applying it to repeated ones is necessarily going to
>>>>>> have
>>>>>> to return only one. But having it look through container
>>>>>> annotation ends
>>>>>> up not being very productive, and may be causing it to be
>>>>>> counter-productive.
>>>>>>
>>>>>> Look-through for this method is not productive because the call
>>>>>> is being
>>>>>> made precisely in the legacy cases when only one annotation was
>>>>>> expected, but a container annotation will only be synthesized when
>>>>>> multiples are present. So look-through does not really help get
>>>>>> "the"
>>>>>> expected annotation. The only case when it would be useful is in the
>>>>>> unlikely case when the container annotation is used explicitly and
>>>>>> contains a single contained annotation.
>>>>> I feel the author of the repeatable annotation type (who "opted
>>>>> in") and the author of the multiple annotations (@Foo @Foo class C
>>>>> ...) bear some responsibility when a legacy caller of
>>>>> getAnnotation(Class<T>) sees one-out-of-many annotations. Someone
>>>>> decided there is no more of "'the' expected annotation".
>>>> Sure, there is some responsibility to be shared by both of those
>>>> parties.The problem is that the call succeeds at all. It should
>>>> probably fail (eg return null) if there are multiples
>>>>
>>>>
>>>>>> It may be counter-productive for three reasons.
>>>>>> The first is because getting a random single annotation in the
>>>>>> presence
>>>>>> of multiples is potentially dangerous since the calling code will
>>>>>> continue without knowing that multiples are present, so legacy
>>>>>> code is
>>>>>> essentially broken, but will not actually fail. It will just be
>>>>>> semantically incorrect.
>>>>> Acknowledged.
>>>>>
>>>>>> The second is because I didn't see (and I may just have missed
>>>>>> it) where
>>>>>> it was defined that if both T and TC were present that T would be
>>>>>> guaranteed to be returned and not some instance within TC.
>>>>>> Example 1.2-3
>>>>>> shows this to be the case but I didn't see that it was specified
>>>>>> behavior rather than just because the T occurred before the TC.
>>>>>> If the
>>>>>> example had been TC and then T would the instance of T be returned?
>>>>> If both @T and @TC are present, we have not yet specified [1]
>>>>> whether get[Declared]Annotation(Class<T>) returns always the lone
>>>>> @T v. always a containerized @T v. something different every time.
>>>>> That's what your feedback is for :-)
>>>>>
>>>>> [1]
>>>>> http://download.java.net/jdk8/docs/api/java/lang/reflect/AnnotatedElement.html#getAnnotation%28java.lang.Class%29
>>>>>
>>>>>> This could be important because existing code to handle this case
>>>>>> checks for the container annotation TC and then checks for the
>>>>>> single
>>>>>> annotation T. However, if checking for T happens to look through TC
>>>>>> and return one of the contained annotations in TC instead of the
>>>>>> lone
>>>>>> T annotation then the lone annotation would not get found.
>>>>> The implementation currently "prefers" a lone @T over a @T inside
>>>>> @TC. If you have a declaration @TC(...) @T class C {} then
>>>>> C.class.getAnnotation(T.class) will return the standalone @T. So
>>>>> existing code to handle this case will still work.
>>>>>
>>>>>> The third is because all of the code that is currently out there
>>>>>> that
>>>>>> needs to check for the previous case, i.e. both T and TC
>>>>>> occurring, will
>>>>>> get a false positive in the simpler case of multiple instances of T
>>>>>> annotations (as per the second part of example 1.2-1 in the doc).
>>>>>> The
>>>>>> getAnnotation(TC) will return the synthesized TC containing all
>>>>>> of the
>>>>>> instances of T, and then getAnnotation(T) will return one of
>>>>>> those same
>>>>>> instances again. Legacy code will assume that the result of
>>>>>> getAnnotation(T) is disjoint from the contained annotations of
>>>>>> the TC
>>>>>> returned by getAnnotation(TC).
>>>>> Acknowledged.
>>>>>
>>>>>> 2. Given that get[Declared]Annotations() is going to change and
>>>>>> return
>>>>>> multiple instances of the same annotation (rather than a single
>>>>>> instance
>>>>>> of a container annotation) existing implementations are going to
>>>>>> have to
>>>>>> be fixed since there is no backwards compatibility there at all.
>>>>> Acknowledged. The category of existing implementations which
>>>>> assume there will never be more than one annotation of a given
>>>>> type in the returned array is in for a surprise.
>>>>>
>>>>> But there is a category of existing implementations which will
>>>>> continue to work fine. Suppose code calls
>>>>> get[Declared]Annotations() and looks first for @T in the array;
>>>>> only if @T is not found does the code look for @TC in the array.
>>>>> This seems like rational behavior for a non-repeating world, as it
>>>>> means one call to get annotations rather than
>>>>> getAnnotation(T.class) plus getAnnotation(TC.class). Now, run the
>>>>> code on SE 8 to get the new behavior of
>>>>> get[Declared]Annotations(). The code will find an @T in the array
>>>>> (the first of many, perhaps) and there will be no search for @TC
>>>>> and everything will be fine. (Assume a top-level @T is returned
>>>>> before containerized @T's.)
>>> I might be misunderstanding you, but I don't see how that category
>>> of legacy application would continue to work. It still won't be
>>> expecting multiples as it looks in the collection, so it will stop
>>> looking once it finds the first one.
>>>
>>>>>> 3. In general, it appears that once an annotation is made
>>>>>> repeatable the
>>>>>> annotation processing code is inevitably going to have to change in
>>>>>> order to handle the repeatability. We were willing to take that hit,
>>>>>> particularly since the new behavior requires opting in, and that
>>>>>> means
>>>>>> that specs could do so at their own discretion. However, the code to
>>>>>> handle both the new and the old (i.e. be able to process both new
>>>>>> repeatable annotations as well as the older idiomatic container
>>>>>> annotations) is a little less intuitive to write than I had hoped it
>>>>>> would be. The easiest way might just be to create a Set of
>>>>>> instances to
>>>>>> avoid duplicates. Not rocket science, just not what I would have
>>>>>> expected.
>>>>> I'm not sure if you are proposing that AnnotatedElement should
>>>>> return Set instances or your framework code should create Set
>>>>> instances. By policy, core reflection does not depend on the rest
>>>>> of the Java SE API, so uses array types as aggregates.
>>> No, sorry, I was just describing what the processor might have to
>>> do, not implying that a Set would be returned by any of the
>>> reflection calls.
>>>
>>>>> So, where are we? Joe and I have always recognized that changing
>>>>> getAnnotation(Class<T>) and get[Declared]Annotations() to look
>>>>> through official containers would affect legacy callers who assume
>>>>> there is at most one @T. A legacy caller which allows for both @T
>>>>> and @TC is perhaps hit harder than the rest - we weren't sure how
>>>>> many legacy callers were this careful, but you imply it's
>>>>> non-trivial.
>>> Yes, and the number of users that would actually make use of this
>>> pattern is admittedly minuscule. Unfortunately, the processing code
>>> generally ends up having to handle it anyway, so the pattern for
>>> processing it is going to be widespread.
>>>
>>>>> Here's an idea. We pondered having the "existing" methods -
>>>>> get[Declared]Annotation(Class<T>) and get[Declared]Annotations() -
>>>>> be unaware of official containers, so they would return exactly
>>>>> what's in the class file. Essentially this is perfect behavioral
>>>>> compatibility. Meanwhile, the new
>>>>> get[Declared]Annotations(Class<T>) methods would look through
>>>>> official containers if present. How does that grab you?
>>> From a compatibility perspective that would be great. Existing code
>>> would be able to handle existing applications, and new code could
>>> easily handle both old and new applications.
>>>
>>> I would just like to mention, though, that while we in EE-land would
>>> like compatibility we are also sensitive to non-legacy users and
>>> don't want to impose changes that too severely hamper the API or
>>> render it unintuitive in the future. We are certainly willing to
>>> make changes to code if necessary, but I was kind of hoping that we
>>> wouldn't be in the situation of existing code apparently working,
>>> but not really. I would be interested in hearing how others view the
>>> idea of the typed version of get[Declared]Annotations behaving
>>> differently than the legacy untyped one.
>
More information about the enhanced-metadata-spec-discuss
mailing list