On 02/26/2015 10:27 PM, Peter Levart wrote:
On 02/26/2015 05:34 PM, Mandy Chung wrote:
The problem is with the default method
AnnotatedElement::getDeclaredAnnotationsByType. If someone has an
external implementation of AnnotatedElement (and one of the lessons
from adding these methods in 8 was that there are other
implementations) then if that external implementation haven’t added
getDeclaredAnnotationsByType they will call into our
AnnotationSupport. This is all fine if that external representation
of AnnotatedElement uses our representation of Annotations, with
Proxies and all. But I suspect that the conditions that would end up
taking the non-proxy code path in the patch, will already fail in
the check:
AnnotationType annoType =
AnnotationType.getInstance(containerClass);
if (annoType == null)
throw invalidContainerException(container, null);
So what is the best thing to do here if the annotation is not Proxy
based and is coming from an implementation of the AnnotatedElement
interface that we don’t control and that is missing the methods
added in 8?
I did a quick search on my corpus and find only one reference to
sun.reflect.annotation.AnnotationType. Looks like external
implementation
doesn't get pass this.
Now I'm missing something. Why would a custom non-Proxy based
annotation not pass the above code? I don't see anything in
AnnotationType implementation that would be dependent on annotation
implementation to be a Proxy. AnnotationType only deals with the
annotation type, which is an interface, not with implementation.
I verified this with the following code:
import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
@CustomAnnTest.Containee("a")
@CustomAnnTest.Containee("b")
@CustomAnnTest.Containee("c")
public class CustomAnnTest {
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Container.class)
public @interface Containee {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Container {
Containee[] value();
}
public static class MyElement implements AnnotatedElement {
@Override
public <T extends Annotation> T getAnnotation(Class<T>
annotationClass) {
for (Annotation ann : getDeclaredAnnotations()) {
if (ann.annotationType() == annotationClass) {
return annotationClass.cast(ann);
}
}
return null;
}
@Override
public Annotation[] getAnnotations() {
return getDeclaredAnnotations();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return new Annotation[] {
new MyContainer(
new MyContainee("A"),
new MyContainee("B"),
new MyContainee("C")
)
};
}
static class MyContainee implements Containee {
final String value;
MyContainee(String value) {
this.value = value;
}
@Override
public String value() {
return value;
}
@Override
public Class<? extends Annotation> annotationType() {
return Containee.class;
}
@Override
public String toString() {
return "@" + annotationType().getName() + "(value=" +
value + ")";
}
}
static class MyContainer implements Container {
final Containee[] value;
MyContainer(Containee ... value) {
this.value = value;
}
@Override
public Containee[] value() {
return value;
}
@Override
public Class<? extends Annotation> annotationType() {
return Container.class;
}
@Override
public String toString() {
return "@" + annotationType().getName() + "(value=" +
Arrays.toString(value) + ")";
}
}
}
static void test(AnnotatedElement ae) {
System.out.println(ae + ":");
System.out.println(Arrays.toString(ae.getDeclaredAnnotations()));
System.out.println(ae.getAnnotation(Container.class));
System.out.println(ae.getAnnotation(Containee.class));
System.out.println(Arrays.toString(ae.getDeclaredAnnotationsByType(Containee.class)));
System.out.println();
}
public static void main(String[] args) {
test(CustomAnnTest.class);
test(new MyElement());
}
}
... it works without problems and prints the expected:
class jdk.test.CustomAnnTest:
[@jdk.test.CustomAnnTest$Container(value=[@jdk.test.CustomAnnTest$Containee(value=a),
@jdk.test.CustomAnnTest$Containee(value=b),
@jdk.test.CustomAnnTest$Containee(value=c)])]
@jdk.test.CustomAnnTest$Container(value=[@jdk.test.CustomAnnTest$Containee(value=a),
@jdk.test.CustomAnnTest$Containee(value=b),
@jdk.test.CustomAnnTest$Containee(value=c)])
null
[@jdk.test.CustomAnnTest$Containee(value=a),
@jdk.test.CustomAnnTest$Containee(value=b),
@jdk.test.CustomAnnTest$Containee(value=c)]
jdk.test.CustomAnnTest$MyElement@3764951d:
[@jdk.test.CustomAnnTest$Container(value=[@jdk.test.CustomAnnTest$Containee(value=A),
@jdk.test.CustomAnnTest$Containee(value=B),
@jdk.test.CustomAnnTest$Containee(value=C)])]
@jdk.test.CustomAnnTest$Container(value=[@jdk.test.CustomAnnTest$Containee(value=A),
@jdk.test.CustomAnnTest$Containee(value=B),
@jdk.test.CustomAnnTest$Containee(value=C)])
null
[@jdk.test.CustomAnnTest$Containee(value=A),
@jdk.test.CustomAnnTest$Containee(value=B),
@jdk.test.CustomAnnTest$Containee(value=C)]