Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8182744

NullPointerException from AnnotationParser.parseArray via Class.isAnnotationPresent after bin-incompat change to ann signature

    XMLWordPrintable

Details

    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.

      Attachments

        Activity

          People

            vromero Vicente Arturo Romero Zaldivar
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated: