JDK-8152174 : Type annotations with a missing type throw NullPointerException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux_ubuntu
  • CPU: x86
  • Submitted: 2016-03-03
  • Updated: 2016-09-27
  • Resolved: 2016-07-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b127Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :


A DESCRIPTION OF THE PROBLEM :
When an annotation is put on a member but the annotation type is missing on the class path, the specification requires the runtime to ignore this annotation, i.e. to act as if the annotation is not present.

This works for all annotations but for type annotations where a NullPointerException is thrown from within the code that resolves the type annotation (sun.reflect.annotation.TypeAnnotationParser).

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Yes

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

EXPECTED VERSUS ACTUAL BEHAVIOR :
The annotation should simply be suppressed but a NullPointerException is thrown.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Caused by: java.lang.NullPointerException
    at sun.reflect.annotation.TypeAnnotationParser.mapTypeAnnotations(TypeAnnotationParser.java:356)
    at sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl.(AnnotatedTypeFactory.java:139)
    at sun.reflect.annotation.AnnotatedTypeFactory.buildAnnotatedType(AnnotatedTypeFactory.java:65)
    at sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedType(TypeAnnotationParser.java:79)
    at java.lang.reflect.Executable.getAnnotatedReturnType0(Executable.java:633)
    at java.lang.reflect.Method.getAnnotatedReturnType(Method.java:648)

REPRODUCIBILITY :
This bug can be reproduced always.


Comments
Case-1 (Doesn't throw Any exception): ================================== abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ cat Foo.java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays; public class Foo { public static void main(String[] args) throws Exception { System.out.println(Arrays.toString(Foo.class.getDeclaredMethod("sample").getDeclaredAnnotations())); //////////////////// The method getAnnotatedReturnType() replaced by getDeclaredAnnotations() System.out.println(Foo.class.getDeclaredMethod("sample").getAnnotatedReturnType()); } @Bar Object sample() { return null; } } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) //////////////////////////////////////////// The enum TYPE_USE is replaced by METHOD //@Target(ElementType.TYPE_USE) @interface Bar { } abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ ==================================================================================================== Output: ###### abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ java -version java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+107-2016-02-24-200204.javare.4520.nc) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+107-2016-02-24-200204.javare.4520.nc, mixed mode) abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ javac Foo.java abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ ls Bar.class Foo.class Foo.java Foo.java~ abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ java Foo [@Bar()] sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@6bc168e5 abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ rm -rf Bar.class abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ ls Foo.class Foo.java Foo.java~ abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ java Foo [] sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@606d8acf abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ ========================================================================================================== Case-2 (throws exception) ######################### abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ cat Foo.java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays; public class Foo { public static void main(String[] args) throws Exception { System.out.println(Arrays.toString(Foo.class.getDeclaredMethod("sample").getDeclaredAnnotations())); System.out.println(Foo.class.getDeclaredMethod("sample").getAnnotatedReturnType()); } @Bar Object sample() { return null; } } @Retention(RetentionPolicy.RUNTIME) //@Target(ElementType.METHOD) @Target(ElementType.TYPE_USE) ///////////////////////////////////// The enum METHOD is replaced by TYPE_USE which occurs exception here @interface Bar { } abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ javac Foo.java abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ ls Bar.class Foo.class Foo.java Foo.java~ abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ java Foo [] sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@7b1d7fff abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ rm -rf Bar.class abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ ls Foo.class Foo.java Foo.java~ abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ java Foo [] Exception in thread "main" java.lang.NullPointerException at sun.reflect.annotation.TypeAnnotationParser.mapTypeAnnotations(TypeAnnotationParser.java:354) at sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl.<init>(AnnotatedTypeFactory.java:140) at sun.reflect.annotation.AnnotatedTypeFactory.buildAnnotatedType(AnnotatedTypeFactory.java:64) at sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedType(TypeAnnotationParser.java:78) at java.lang.reflect.Executable.getAnnotatedReturnType0(Executable.java:642) at java.lang.reflect.Method.getAnnotatedReturnType(Method.java:670) at Foo.main(Foo.java:10) abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$
27-09-2016

Based On JLS 9.6.4.2. @Retention ++++++++++++++++++++++++++++ Annotations may be present only in source code, or they may be present in the binary form of a class or interface. An annotation that is present in the binary form may or may not be available at run time via the reflection libraries of the Java SE platform. The annotation type java.lang.annotation.Retention is used to choose among these possibilities. If an annotation a corresponds to a type T, and T has a (meta-)annotation m that corresponds to java.lang.annotation.Retention, then: If m has an element whose value is java.lang.annotation.RetentionPolicy.SOURCE, then a Java compiler must ensure that a is not present in the binary representation of the class or interface in which a appears. If m has an element whose value is java.lang.annotation.RetentionPolicy.CLASS or java.lang.annotation.RetentionPolicy.RUNTIME, then a Java compiler must ensure that a is represented in the binary representation of the class or interface in which a appears, unless m annotates a local variable declaration. An annotation on a local variable declaration is never retained in the binary representation. In addition, if m has an element whose value is java.lang.annotation.RetentionPolicy.RUNTIME, the reflection libraries of the Java SE platform must make a available at run time. If T does not have a (meta-)annotation m that corresponds to java.lang.annotation.Retention, then a Java compiler must treat T as if it does have such a meta-annotation m with an element whose value is java.lang.annotation.RetentionPolicy.CLASS.
26-09-2016

Test result: ######### OS: Windows 7 64-bit JDK: 8uXX : Fail 9ea : Fail Output: ********** abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ javac -version javac 9-ea abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ javac Foo.java abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ rm -rf Bar.class abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$ java Foo Exception in thread "main" java.lang.NullPointerException at sun.reflect.annotation.TypeAnnotationParser.mapTypeAnnotations(TypeAnnotationParser.java:354) at sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl.<init>(AnnotatedTypeFactory.java:140) at sun.reflect.annotation.AnnotatedTypeFactory.buildAnnotatedType(AnnotatedTypeFactory.java:64) at sun.reflect.annotation.TypeAnnotationParser.buildAnnotatedType(TypeAnnotationParser.java:78) at java.lang.reflect.Executable.getAnnotatedReturnType0(Executable.java:642) at java.lang.reflect.Method.getAnnotatedReturnType(Method.java:670) at Foo.main(Foo.java:8) abhijit@abhijit-VirtualBox:/media/sf_ora/ji/core-libs$
26-09-2016

According to submitter, - run javac Foo.java - delete Bar.class By definition of the JVLS, annotations are not required on the class path to successfully run a program as they only represent metadata. - Now run "java Foo". - Observe a NullPointerException.
26-09-2016

Review thread: http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-July/042213.html
07-07-2016

Looks like a missing null-check in TypeAnnotationParser.mapTypeAnnotations compared to sun.reflect.annotation.AnnotationParser.parseAnnotations2.
07-07-2016

Shorter Test case (provided by submitter): ################################## class Foo { public static void main(String[] args) throws Exception { Foo.class.getDeclaredMethod("sample").getAnnotatedReturnType(); } @Bar Object sample() { return null; } } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) @interface Bar { }
17-03-2016