Details
-
Bug
-
Status: Open
-
P4
-
Resolution: Unresolved
-
8, 9
-
x86_64
-
linux
Description
FULL PRODUCT VERSION :
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux … 4.10.0-22-generic #24-Ubuntu SMP Mon May 22 17:43:20 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
After making a binary-incompatible change to the definition of an annotation, some reflective calls dealing with annotations yield undeclared `NullPointerException`s. (`NullPointerException` is a documented possibility, but for an entirely different reason.) Known to occur for at least `Class.getAnnotation` and `Class.isAnnotationPresent`, but there may be other triggers.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached demo script.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
single
true
<some kind of AnnotationTypeMismatchException>
true
[single]
true
<some kind of AnnotationTypeMismatchException>
ACTUAL -
true
single
true
Exception in thread "main" java.lang.annotation.AnnotationTypeMismatchException: Incorrectly typed data found for annotation element public abstract java.lang.String[] test.Ann.value() (Found data of type class java.lang.String[single])
at sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy.generateException(AnnotationTypeMismatchExceptionProxy.java:57)
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:84)
at com.sun.proxy.$Proxy1.value(Unknown Source)
at test.Demo.main(Demo.java:6)
true
[single]
java.lang.NullPointerException
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:532)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at java.lang.Class.getAnnotation(Class.java:3415)
at java.lang.reflect.AnnotatedElement.isAnnotationPresent(AnnotatedElement.java:258)
at java.lang.Class.isAnnotationPresent(Class.java:3425)
at test.Demo.main(Demo.java:5)
Exception in thread "main" java.lang.NullPointerException
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:532)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at java.lang.Class.getAnnotation(Class.java:3415)
at test.Demo.main(Demo.java:9)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Both unexpected errors come down to
java.lang.NullPointerException
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:532)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at …
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
#!/bin/sh
rm -rf src bin
mkdir -p src/test
cat >src/test/Demo.java <<EOF
package test;
public class Demo {
public static void main(String[] args) {
System.out.println(Klazz.class.isAnnotationPresent(Ann.class));
System.out.println(Klazz.class.getAnnotation(Ann.class).value());
}
}
EOF
cat >src/test/Ann.java <<EOF
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String value();
}
EOF
cat >src/test/Klazz.java <<EOF
package test;
@Ann("single")
public class Klazz {}
EOF
mkdir bin
javac -d bin -classpath bin src/test/*.java
java -cp bin test.Demo
cat >src/test/Demo.java <<EOF
package test;
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
System.out.println(Klazz.class.isAnnotationPresent(Ann.class));
System.out.println(Arrays.toString(Klazz.class.getAnnotation(Ann.class).value()));
}
}
EOF
cat >src/test/Ann.java <<EOF
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String[] value();
}
EOF
javac -d bin -classpath bin src/test/Demo.java src/test/Ann.java
java -cp bin test.Demo
javac -d bin -classpath bin src/test/Klazz.java
java -cp bin test.Demo
cat >src/test/Demo.java <<EOF
package test;
public class Demo {
public static void main(String[] args) {
try {
System.out.println(Klazz.class.isAnnotationPresent(Ann.class));
} catch (Exception x) {
x.printStackTrace();
}
System.out.println(Klazz.class.getAnnotation(Ann.class).value());
}
}
EOF
cat >src/test/Ann.java <<EOF
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String value();
}
EOF
javac -d bin -classpath bin src/test/Demo.java src/test/Ann.java
java -cp bin test.Demo
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Catch undeclared unchecked exceptions when calling annotation-related reflective methods.
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux … 4.10.0-22-generic #24-Ubuntu SMP Mon May 22 17:43:20 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
After making a binary-incompatible change to the definition of an annotation, some reflective calls dealing with annotations yield undeclared `NullPointerException`s. (`NullPointerException` is a documented possibility, but for an entirely different reason.) Known to occur for at least `Class.getAnnotation` and `Class.isAnnotationPresent`, but there may be other triggers.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached demo script.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
single
true
<some kind of AnnotationTypeMismatchException>
true
[single]
true
<some kind of AnnotationTypeMismatchException>
ACTUAL -
true
single
true
Exception in thread "main" java.lang.annotation.AnnotationTypeMismatchException: Incorrectly typed data found for annotation element public abstract java.lang.String[] test.Ann.value() (Found data of type class java.lang.String[single])
at sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy.generateException(AnnotationTypeMismatchExceptionProxy.java:57)
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:84)
at com.sun.proxy.$Proxy1.value(Unknown Source)
at test.Demo.main(Demo.java:6)
true
[single]
java.lang.NullPointerException
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:532)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at java.lang.Class.getAnnotation(Class.java:3415)
at java.lang.reflect.AnnotatedElement.isAnnotationPresent(AnnotatedElement.java:258)
at java.lang.Class.isAnnotationPresent(Class.java:3425)
at test.Demo.main(Demo.java:5)
Exception in thread "main" java.lang.NullPointerException
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:532)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at java.lang.Class.getAnnotation(Class.java:3415)
at test.Demo.main(Demo.java:9)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Both unexpected errors come down to
java.lang.NullPointerException
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:532)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at …
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
#!/bin/sh
rm -rf src bin
mkdir -p src/test
cat >src/test/Demo.java <<EOF
package test;
public class Demo {
public static void main(String[] args) {
System.out.println(Klazz.class.isAnnotationPresent(Ann.class));
System.out.println(Klazz.class.getAnnotation(Ann.class).value());
}
}
EOF
cat >src/test/Ann.java <<EOF
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String value();
}
EOF
cat >src/test/Klazz.java <<EOF
package test;
@Ann("single")
public class Klazz {}
EOF
mkdir bin
javac -d bin -classpath bin src/test/*.java
java -cp bin test.Demo
cat >src/test/Demo.java <<EOF
package test;
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
System.out.println(Klazz.class.isAnnotationPresent(Ann.class));
System.out.println(Arrays.toString(Klazz.class.getAnnotation(Ann.class).value()));
}
}
EOF
cat >src/test/Ann.java <<EOF
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String[] value();
}
EOF
javac -d bin -classpath bin src/test/Demo.java src/test/Ann.java
java -cp bin test.Demo
javac -d bin -classpath bin src/test/Klazz.java
java -cp bin test.Demo
cat >src/test/Demo.java <<EOF
package test;
public class Demo {
public static void main(String[] args) {
try {
System.out.println(Klazz.class.isAnnotationPresent(Ann.class));
} catch (Exception x) {
x.printStackTrace();
}
System.out.println(Klazz.class.getAnnotation(Ann.class).value());
}
}
EOF
cat >src/test/Ann.java <<EOF
package test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann {
String value();
}
EOF
javac -d bin -classpath bin src/test/Demo.java src/test/Ann.java
java -cp bin test.Demo
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Catch undeclared unchecked exceptions when calling annotation-related reflective methods.