RFR: 8004912: Repeating annotations - getAnnotationsByType is not working as expected
Joel Borggrén-Franck
joel.franck at oracle.com
Tue Oct 22 15:26:08 UTC 2013
Hi Peter,
On my way to dinner I realized we have a problem for inherited annotations there are inherited over two (or more) declarations. I believe this is essentially the issue you highlighted though I will look into this tomorrow.
On 22 okt 2013, at 21:20, Peter Levart <peter.levart at gmail.com> wrote:
> I think the problem could be solved in two ways:
>
> - by explicitly scanning the inheritance chain for the 1st class that has the annotations of type T present directly or indirectly (by containment).
>
Yes, this is how I solved it for javax.lang.model and this is how I think we should fix this.
> - by "canonicalizing" the representation of the repeating annotations in the class file attributes. By this I mean that each repeating annotation is placed inside it's container at compile-time even if it is a single annotation of a particular type. This would mean that some features like specifying different @Targets or @Retentions for repeating annotation types and their containers would be prohibited and the specification would have to be changed. But I think this way the "inheritance" aspect of repeating annotations would be consistent even if not "looking through" containers (by using the old JDK7 API)...
>
> The "canonicalization" could be performed at runtime though, and I think there were such attempts already in the past. What happened to them?
>
There hasn't been any attempt to do this at runtime. Fwiw I don't think this is worth the complexity unless someone proves the iterative lookup on super types is a performance issue.
cheers
/Joel
>
> Regards, Peter
>
> On 10/22/2013 02:57 PM, Peter Levart wrote:
>> Hi,
>>
>> The spec says:
>>
>> When the new get[Declared]AnnotationsByType(Class<T>) methods are
>> called for a repeatable annotation type T, the question is how to extend the policy
>> to handle multiple annotations of type T on the superclass and/or subclass. Oracle
>> proposes the following policy for Java SE 8:
>>
>> • If a class declaration does not have either a "directly present" annotation of
>> type T or an "indirectly present by containment" annotation of type T, the class
>> declaration may be "associated" with an annotation of type T due to inheritance.
>>
>> • If a class declaration does have either a "directly present" annotation of type T
>> or an "indirectly present by containment" annotation of type T, the annotation
>> is deemed to "override" every annotation of type T which is "associated" with
>> the superclass.
>>
>> This policy for Java SE 8 is reified in the following definitions:
>>
>> • An annotation A is directly present on an element E if E has a
>> RuntimeVisibleAnnotations or RuntimeVisibleParameterAnnotations or
>> RuntimeVisibleTypeAnnotations attribute, and the attribute contains A.1.2 Core Reflection API REPEATING ANNOTATIONS
>> 12
>>
>> • An annotation A is indirectly present on an element E if E has a
>> RuntimeVisibleAnnotations or RuntimeVisibleParameterAnnotations or
>> RuntimeVisibleTypeAnnotations attribute, and A's type is repeatable, and the
>> attribute contains exactly one annotation whose value element contains A and
>> whose type is the containing annotation type of A's type (§9.6).
>>
>> • An annotation A is present on an element E if either:
>> - A is directly present on E; or
>> - No annotation of A's type is directly present on E, and E is a class, and A's type
>> is inheritable (§9.6.3.3), and A is present on the superclass of E.
>>
>> • An annotation A is associated with an element E if either:
>> - A is directly or indirectly present on E; or
>> - No annotation of A's type is directly or indirectly present on E, and E is a class,
>> and A's type is inheritable (§9.6.3.3), and A is associated with the superclass
>> of E.
>>
>>
>> So I guess E.class.getAnnotations() returns the annotations "present" on the E
>> and E.class.getAnnotationsByType(A.class) returns the annotations of type A "associated" with E
>>
>> Am I right?
>>
>> Let's just focus on "associated" part now - the getAnnotationsByType method. The following test:
>>
>> http://cr.openjdk.java.net/~plevart/jdk8-tl/RepearingAnnotations/InheritedRepeatingAnnotationsTest.java
>>
>> dumps @Repeatable @Inherited annotations "associated" with the following classes:
>>
>> @Ann(10)
>> class A1 {}
>>
>> @Ann(20)
>> class A2 extends A1 {}
>>
>> class A3 extends A2 {}
>>
>>
>> @Ann(10) @Ann(11)
>> class B1 {}
>>
>> @Ann(20)
>> class B2 extends B1 {}
>>
>> class B3 extends B2 {}
>>
>>
>> @Ann(10)
>> class C1 {}
>>
>> @Ann(20) @Ann(21)
>> class C2 extends C1 {}
>>
>> class C3 extends C2 {}
>>
>>
>> @Ann(10) @Ann(11)
>> class D1 {}
>>
>> @Ann(20) @Ann(21)
>> class D2 extends D1 {}
>>
>> class D3 extends D2 {}
>>
>>
>> Here's the output:
>>
>>
>> class A2: [@Ann(value=20)]
>> class B2: [@Ann(value=20)]
>> class C2: [@Ann(value=20), @Ann(value=21)]
>> class D2: [@Ann(value=20), @Ann(value=21)]
>>
>> class A3: [@Ann(value=20)]
>> class B3: [@Ann(value=10), @Ann(value=11), @Ann(value=20)]
>> class C3: [@Ann(value=10), @Ann(value=20), @Ann(value=21)]
>> class D3: [@Ann(value=20), @Ann(value=21)]
>>
>>
>>
>> Class B3 is showing @Ann(10) and @Ann(11), while class C3 is showing @Ann(10) as being "associated" with them, but they should not, right?
>>
>> Class B3 should show the same annotations as B2 and class C3 should show the same annotations as class C2, I think.
>>
>>
>> Regards, Peter
>>
>>
>> On 10/22/2013 01:03 PM, Joel Borggrén-Franck wrote:
>>> Hi Peter,
>>>
>>> Spec is here:
>>> http://cr.openjdk.java.net/~abuckley/8misc.pdf
>>>
>>>
>>> FYI I pushed this before I saw your mail but I do think the code is correct. An extra pair of eyes would be great though!
>>>
>>> FWIW I suspect we can be better with regards to allocation especially if we optimize for the common case where there is either a single annotation or a single container, but that will have to be a follow up.
>>>
>>> Btw there are a lot of extra test cases in the langtools repository (!?!) look in langtools/test/tools/javac/annotations/repeatingAnnotations/combo/ReflectionTest.java
>>>
>>> cheers
>>> /Joel
>>>
>>> On 22 okt 2013, at 18:50, Peter Levart
>>> <peter.levart at gmail.com>
>>> wrote:
>>>
>>>
>>>> Hi, I would just like to ask for a pointer to some specification document that describes inheritance of repeating annotations. I couldn't find one on the net.
>>>>
>>>> I have a feeling there's something wrong with the logic of AnnotationsSuport.getAssociatedAnnotations. Why? Because it is based on two maps: declaredAnnotations map and allAnnotations map. The later is a map of inherited and/or declared annotations which is aggregated without the knowledge of repeating annotations (the containers). I doubt this map keeps enough information to reconstruct a sound set of inherited and/or declared repeating annotations in all situations.
>>>>
>>>> But I'd like to 1st see the specification before showing you some examples where problems arise.
>>>>
>>>> Regards, Peter
>>>>
>>>> On 10/22/2013 12:21 PM, Joel Borggrén-Franck wrote:
>>>>
>>>>> Hi Andreas,
>>>>>
>>>>> A few nits:
>>>>>
>>>>> Class.java:
>>>>>
>>>>> import java.util.Collection;
>>>>> +import java.util.Collections;
>>>>> import java.util.HashSet;
>>>>>
>>>>> unused import.
>>>>>
>>>>> AnnotationSupport.java:
>>>>>
>>>>> + /**
>>>>> + * Equivalent to calling {@code getDirectlyAndIndirectlyPresentAnnotations(
>>>>> + * annotations, annoClass, false)}.
>>>>> + */
>>>>>
>>>>> I think it is equivalent to annotations, annoClass, true
>>>>>
>>>>> Otherwise looks good. I can sponsor this fix.
>>>>>
>>>>> cheers
>>>>> /Joel
>>>>>
>>>>> On 21 okt 2013, at 21:01, Andreas Lundblad
>>>>> <andreas.lundblad at oracle.com>
>>>>> wrote:
>>>>>
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> New revision up for review:
>>>>>>
>>>>>>
>>>>>> http://aoeu.se/webrevs/8019420-and-8004912/webrev.01
>>>>>>
>>>>>>
>>>>>> The following has been addressed since webrev.00:
>>>>>>
>>>>>> - Order of directly / indirectly present annotations now respects the order of the keys in the given map of annotations.
>>>>>>
>>>>>> - A new test has been added to test the above behavior.
>>>>>>
>>>>>> best regards,
>>>>>> Andreas
>>>>>>
>>>>>>
>>>>>> ----- Original Message -----
>>>>>> From:
>>>>>> andreas.lundblad at oracle.com
>>>>>>
>>>>>> To:
>>>>>> core-libs-dev at openjdk.java.net
>>>>>>
>>>>>> Sent: Wednesday, October 16, 2013 4:00:08 PM GMT +01:00 Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna
>>>>>> Subject: RFR: 8004912: Repeating annotations - getAnnotationsByType is not working as expected
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Please review the fix for JDK-8004912 and JDK-8019420 below.
>>>>>>
>>>>>> Description:
>>>>>>
>>>>>> The behavior of Class.get[Declared]AnnotationsByType was wrong. These methods delegate to sun.reflect.annotation.AnnotationSupport which has been rewritten.
>>>>>>
>>>>>> NonInheritableContainee.java is added and contains the test referred to in JDK-8019420.
>>>>>>
>>>>>> RepeatedUnitTest.java have been updated to include the test cases in JDK-8004912.
>>>>>>
>>>>>> There are more tests available in tl/langtools/test/tools/javac/annotations/repeatingAnnotations/combo/ReflectionTest.java (NB. this file is in the langtools repo)
>>>>>>
>>>>>>
>>>>>> Link to web review:
>>>>>>
>>>>>> http://cr.openjdk.java.net/~alundblad/8019420-and-8004912/
>>>>>>
>>>>>>
>>>>>> Link to bug reports:
>>>>>>
>>>>>> https://bugs.openjdk.java.net/browse/JDK-8004912
>>>>>> https://bugs.openjdk.java.net/browse/JDK-8019420
>>>>>>
>>>>>>
>>>>>>
>>>>>> -- Andreas Lundblad
>>>>>>
>>
>
More information about the core-libs-dev
mailing list