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).
- 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?
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
<http://cr.openjdk.java.net/%7Eplevart/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.lev...@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.lundb...@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.lundb...@oracle.com
To:core-libs-dev@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