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

Method and field annotation parsing in VM does not work

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 5.0
    • 1.4.0
    • hotspot
    • b32
    • generic
    • generic

      DEFAULTS

      When the following class is compiled, the (private) annotationDefault field in the Method object for "engineer" indicates a default of "[unimplemented]" (which should be the default for date), and the annotationDefault field in the method object for "date" is null. The latter fact is clearly demonstrated by the following short program:
      import java.lang.annotation.*;
      import java.lang.reflect.*;

      public class Bug {
          /**
           * Returns the raw default value pertaining to the annotation type member
           * indicated by the specified Method object, or null if no default exists.
           */
          private static byte[] getRawDefaultValue(Method annotationTypeMember) {
              try {
                  return (byte[]) defaultField.get(annotationTypeMember);
              } catch(Exception e) {
                  throw new AssertionError(e);
              }
          }
          private static Field defaultField;
          static {
              try {
                  defaultField = Method.class.getDeclaredField("annotationDefault");
              } catch(Exception e) {
                  throw new AssertionError(e);
              }
              defaultField.setAccessible(true);
          }

          public static void main(String[] args) throws Exception {
              Class c = RequestForEnhancement.class;
              Method engineer = c.getMethod("engineer", new Class[]{});
              Method date = c.getMethod("date", new Class[]{});
              System.out.println(getRawDefaultValue(engineer));
              System.out.println(getRawDefaultValue(date));
          }
      }


      /**
       * Describes the "request-for-enhancement" (RFE) that led to the presence of
       * the annotated API element.
       */
      @Visibility(RUNTIME)
      @interface RequestForEnhancement {
          int id(); // No default - must be specified in each annotation
          String synopsis(); // No default - must be specified in each annotation
          String engineer() default "[unassigned]";
          String date() default "[unimplemented]";
      }

      METHODS

      When the following class is compiled and run, it shows that two of the three methods (scalarTypesAcceptDefaultMethod and
      scalarTypesOverrideDefaultMethod) have no annotations (null), even though all three methods have annotations. The defaults shown for the first method appear to be incorrect as well:

      import static java.lang.annotation.VisibilityLevel.RUNTIME;

      import java.lang.annotation.*;
      import java.util.*;
      import java.lang.reflect.*;

      public class Bug {
          private static final Class[] X = new Class[0];

          public static void main(String[] args) throws Exception {
              printByteArray(getRawMethodAnnotations(Bug.class.getMethod("scalarTypesMethod", X)));
              printByteArray(getRawMethodAnnotations(Bug.class.getMethod("scalarTypesOverrideDefaultMethod", X)));
              printByteArray(getRawMethodAnnotations(Bug.class.getMethod("scalarTypesAcceptDefaultMethod", X)));
          }

          /**
           * Returns the raw annotations for the specified method.
           */
          private static byte[] getRawMethodAnnotations(Method m) {
              try {
                  return (byte[]) methodAnnotationsField.get(m);
              } catch(Exception e) {
                  throw new AssertionError(e);
              }
          }
          private static Field methodAnnotationsField;
          static {
              try {
                  methodAnnotationsField =
                      Method.class.getDeclaredField("annotations");
              } catch(Exception e) {
                  throw new AssertionError(e);
              }
              methodAnnotationsField.setAccessible(true);
          }

          private static void printByteArray(byte[] a) {
              if (a==null) {
                  System.out.println("null");
                  return;
              }
              System.out.print("[");
              for (byte b : a)
                  System.out.print(b+" ");
              System.out.println("]");
          }


          // ANNOTATED METHODS

          @ScalarTypes (
              b = 1,
              s = 2,
              i = 3,
              l = 4L,
              c = '5',
              f = 6.0f,
              d = 7.0,
              bool = true,
              str = "custom",
              cls = Map.class,
              e = MOE
          )
          public void scalarTypesMethod() { }

          @ScalarTypesWithDefault ( )
          public void scalarTypesAcceptDefaultMethod() { }

          @ScalarTypesWithDefault (
              b = 1,
              s = 2,
              i = 3,
              l = 4L,
              c = '5',
              f = 6.0f,
              d = 7.0,
              bool = true,
              str = "custom",
              cls = Map.class,
              e = MOE
          )
          public void scalarTypesOverrideDefaultMethod() { }
      }

      // Helper types

      enum Stooge { LARRY, MOE, CURLY }

      // ANNOTATION TYPES

      @Visibility(RUNTIME) @interface ScalarTypes {
          byte b();
          short s();
          int i();
          long l();
          char c();
          float f();
          double d();
          boolean bool();
          String str();
          Class cls();
          Stooge e();
      }

      @Visibility(RUNTIME) @interface ScalarTypesWithDefault {
          byte b() default 11;
          short s() default 12;
          int i() default 13;
          long l() default 14;
          char c() default 'V';
          float f() default 16.0f;
          double d() default 17.0;
          boolean bool() default false;
          String str() default "default";
          Class cls() default Class.class;
          Stooge e() default LARRY;
      }

      When run, the following output is appears:

      [0 1 0 90 0 11 0 65 73 0 66 0 67 73 0 68 0 69 73 0 70 0 71 74 0 72 0 74 73 0 75 0 76 70 0 77 0 78 68 0 79 0 81 73 0 66 0 82 115 0 83 0 84 99 0 85 0 86 101 0 87 0 88 ]
      null
      null


      *****************************************************************************

      FIELDS

      This program shows that all three annotated fields have no annotations (null):


      import static java.lang.annotation.VisibilityLevel.RUNTIME;

      import java.lang.annotation.*;
      import java.util.*;
      import java.lang.reflect.*;

      public class Bug2 {
          private static final Class[] X = new Class[0];

          public static void main(String[] args) throws Exception {
              printByteArray(getRawFieldAnnotations(Bug2.class.getField("scalarTypesField")));
              printByteArray(getRawFieldAnnotations(Bug2.class.getField("scalarTypesOverrideDefaultField")));
              printByteArray(getRawFieldAnnotations(Bug2.class.getField("scalarTypesAcceptDefaultField")));
          }

          /**
           * Returns the raw annotations for the specified field.
           */
          private static byte[] getRawFieldAnnotations(Field f) {
              try {
                  return (byte[]) fieldAnnotationsField.get(f);
              } catch(Exception e) {
                  throw new AssertionError(e);
              }
          }

          private static Field fieldAnnotationsField;
          static {
              try {
                  fieldAnnotationsField =
                      Field.class.getDeclaredField("annotations");
              } catch(Exception e) {
                  throw new AssertionError(e);
              }
               fieldAnnotationsField.setAccessible(true);
          }

          private static void printByteArray(byte[] a) {
              if (a==null) {
                  System.out.println("null");
                  return;
              }
              System.out.print("[");
              for (byte b : a)
                  System.out.print(b+" ");
              System.out.println("]");
          }


          // ANNOTATED FIELDS
          @ScalarTypes (
              b = 1,
              s = 2,
              i = 3,
              l = 4L,
              c = '5',
              f = 6.0f,
              d = 7.0,
              bool = true,
              str = "custom",
              cls = Map.class,
              e = MOE
          )
          public int scalarTypesField;

          @ScalarTypesWithDefault ( )
          public int scalarTypesAcceptDefaultField;

          @ScalarTypesWithDefault (
              b = 1,
              s = 2,
              i = 3,
              l = 4L,
              c = '5',
              f = 6.0f,
              d = 7.0,
              bool = true,
              str = "custom",
              cls = Map.class,
              e = /* XXX Stooge. */ MOE
          )
          public int scalarTypesOverrideDefaultField;
      }

      // Helper types

      enum Stooge { LARRY, MOE, CURLY }

      // ANNOTATION TYPES

      @Visibility(RUNTIME) @interface ScalarTypes {
          byte b();
          short s();
          int i();
          long l();
          char c();
          float f();
          double d();
          boolean bool();
          String str();
          Class cls();
          Stooge e();
      }

      @Visibility(RUNTIME) @interface ScalarTypesWithDefault {
          byte b() default 11;
          short s() default 12;
          int i() default 13;
          long l() default 14;
          char c() default 'V';
          float f() default 16.0f;
          double d() default 17.0;
          boolean bool() default false;
          String str() default "default";
          Class cls() default Class.class;
          Stooge e() default LARRY;
      }


      It prints:
      null
      null
      null
      **************************************************

            kbr Kenneth Russell (Inactive)
            jjb Josh Bloch
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: