-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
8u66, 9
-
generic
-
generic
FULL PRODUCT VERSION :
A DESCRIPTION OF THE PROBLEM :
Type annotations on type variable bounds are not always resolved correctly by the Java core reflection API if the bound is put on a parameterized type that is not an interface type or on another type variable.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
true
true
true
true
ACTUAL -
false
true
true
true
false
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
public class Foo<T,
S extends @Sample T,
U extends @Sample Runnable,
V extends @Sample String,
W extends @Sample List<?>,
X extends @Sample ArrayList<?>> {
public static void main(String[] args) {
System.out.println(Foo.class.getTypeParameters()[1].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[2].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[3].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[4].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[5].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface Sample { }
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None, it is however simple to see why this is happening. javac writes bounds that are "non-primary", i.e. not an interface type at index 1 instead of 0 even if there is no class type bound. The reflection API does not correctly account for this.
The type references in the class file can be interpreted as follows using ASM:
System.out.println(new TypeReference(285278208).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285344000).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285409280).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285475072).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285540352).getTypeParameterBoundIndex());
printing
0
1
0
1
0
This does not make much sense in the first place and this is neither specified in this way in the JVMS.
A DESCRIPTION OF THE PROBLEM :
Type annotations on type variable bounds are not always resolved correctly by the Java core reflection API if the bound is put on a parameterized type that is not an interface type or on another type variable.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
true
true
true
true
ACTUAL -
false
true
true
true
false
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
public class Foo<T,
S extends @Sample T,
U extends @Sample Runnable,
V extends @Sample String,
W extends @Sample List<?>,
X extends @Sample ArrayList<?>> {
public static void main(String[] args) {
System.out.println(Foo.class.getTypeParameters()[1].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[2].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[3].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[4].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
System.out.println(Foo.class.getTypeParameters()[5].getAnnotatedBounds()[0].isAnnotationPresent(Sample.class));
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface Sample { }
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None, it is however simple to see why this is happening. javac writes bounds that are "non-primary", i.e. not an interface type at index 1 instead of 0 even if there is no class type bound. The reflection API does not correctly account for this.
The type references in the class file can be interpreted as follows using ASM:
System.out.println(new TypeReference(285278208).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285344000).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285409280).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285475072).getTypeParameterBoundIndex());
System.out.println(new TypeReference(285540352).getTypeParameterBoundIndex());
printing
0
1
0
1
0
This does not make much sense in the first place and this is neither specified in this way in the JVMS.
- relates to
-
JDK-8202469 (ann) Type annotations on type variable bounds that are also type variables are lost
-
- Closed
-