src/share/classes/sun/reflect/annotation/AnnotationParser.java

Print this page




  42 /**
  43  * Parser for Java programming language annotations.  Translates
  44  * annotation byte streams emitted by compiler into annotation objects.
  45  *
  46  * @author  Josh Bloch
  47  * @since   1.5
  48  */
  49 public class AnnotationParser {
  50     /**
  51      * Parses the annotations described by the specified byte array.
  52      * resolving constant references in the specified constant pool.
  53      * The array must contain an array of annotations as described
  54      * in the RuntimeVisibleAnnotations_attribute:
  55      *
  56      *   u2 num_annotations;
  57      *   annotation annotations[num_annotations];
  58      *
  59      * @throws AnnotationFormatError if an annotation is found to be
  60      *         malformed.
  61      */
  62     public static Map<Class, Annotation> parseAnnotations(
  63                 byte[] rawAnnotations,
  64                 ConstantPool constPool,
  65                 Class container) {
  66         if (rawAnnotations == null)
  67             return Collections.emptyMap();
  68 
  69         try {
  70             return parseAnnotations2(rawAnnotations, constPool, container);
  71         } catch(BufferUnderflowException e) {
  72             throw new AnnotationFormatError("Unexpected end of annotations.");
  73         } catch(IllegalArgumentException e) {
  74             // Type mismatch in constant pool
  75             throw new AnnotationFormatError(e);
  76         }
  77     }
  78 
  79     private static Map<Class, Annotation> parseAnnotations2(
  80                 byte[] rawAnnotations,
  81                 ConstantPool constPool,
  82                 Class container) {
  83         Map<Class, Annotation> result = new LinkedHashMap<Class, Annotation>();

  84         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
  85         int numAnnotations = buf.getShort() & 0xFFFF;
  86         for (int i = 0; i < numAnnotations; i++) {
  87             Annotation a = parseAnnotation(buf, constPool, container, false);
  88             if (a != null) {
  89                 Class klass = a.annotationType();
  90                 AnnotationType type = AnnotationType.getInstance(klass);
  91                 if (type.retention() == RetentionPolicy.RUNTIME)
  92                     if (result.put(klass, a) != null)
  93                         throw new AnnotationFormatError(
  94                             "Duplicate annotation for class: "+klass+": " + a);
  95             }
  96         }
  97         return result;
  98     }
  99 
 100     /**
 101      * Parses the parameter annotations described by the specified byte array.
 102      * resolving constant references in the specified constant pool.
 103      * The array must contain an array of annotations as described
 104      * in the RuntimeVisibleParameterAnnotations_attribute:
 105      *
 106      *    u1 num_parameters;
 107      *    {
 108      *        u2 num_annotations;
 109      *        annotation annotations[num_annotations];
 110      *    } parameter_annotations[num_parameters];
 111      *
 112      * Unlike parseAnnotations, rawAnnotations must not be null!
 113      * A null value must be handled by the caller.  This is so because
 114      * we cannot determine the number of parameters if rawAnnotations
 115      * is null.  Also, the caller should check that the number
 116      * of parameters indicated by the return value of this method
 117      * matches the actual number of method parameters.  A mismatch
 118      * indicates that an AnnotationFormatError should be thrown.
 119      *
 120      * @throws AnnotationFormatError if an annotation is found to be
 121      *         malformed.
 122      */
 123     public static Annotation[][] parseParameterAnnotations(
 124                     byte[] rawAnnotations,
 125                     ConstantPool constPool,
 126                     Class container) {
 127         try {
 128             return parseParameterAnnotations2(rawAnnotations, constPool, container);
 129         } catch(BufferUnderflowException e) {
 130             throw new AnnotationFormatError(
 131                 "Unexpected end of parameter annotations.");
 132         } catch(IllegalArgumentException e) {
 133             // Type mismatch in constant pool
 134             throw new AnnotationFormatError(e);
 135         }
 136     }
 137 
 138     private static Annotation[][] parseParameterAnnotations2(
 139                     byte[] rawAnnotations,
 140                     ConstantPool constPool,
 141                     Class container) {
 142         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
 143         int numParameters = buf.get() & 0xFF;
 144         Annotation[][] result = new Annotation[numParameters][];
 145 
 146         for (int i = 0; i < numParameters; i++) {
 147             int numAnnotations = buf.getShort() & 0xFFFF;
 148             List<Annotation> annotations =
 149                 new ArrayList<Annotation>(numAnnotations);
 150             for (int j = 0; j < numAnnotations; j++) {
 151                 Annotation a = parseAnnotation(buf, constPool, container, false);
 152                 if (a != null) {
 153                     AnnotationType type = AnnotationType.getInstance(
 154                                               a.annotationType());
 155                     if (type.retention() == RetentionPolicy.RUNTIME)
 156                         annotations.add(a);
 157                 }
 158             }
 159             result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
 160         }
 161         return result;


 171      * structure" as described in the RuntimeVisibleAnnotations_attribute:
 172      *
 173      * annotation {
 174      *    u2    type_index;
 175      *       u2    num_member_value_pairs;
 176      *       {    u2    member_name_index;
 177      *             member_value value;
 178      *       }    member_value_pairs[num_member_value_pairs];
 179      *    }
 180      * }
 181      *
 182      * Returns the annotation, or null if the annotation's type cannot
 183      * be found by the VM, or is not a valid annotation type.
 184      *
 185      * @param exceptionOnMissingAnnotationClass if true, throw
 186      * TypeNotPresentException if a referenced annotation type is not
 187      * available at runtime
 188      */
 189     private static Annotation parseAnnotation(ByteBuffer buf,
 190                                               ConstantPool constPool,
 191                                               Class container,
 192                                               boolean exceptionOnMissingAnnotationClass) {
 193         int typeIndex = buf.getShort() & 0xFFFF;
 194         Class annotationClass = null;
 195         String sig = "[unknown]";
 196         try {
 197             try {
 198                 sig = constPool.getUTF8At(typeIndex);
 199                 annotationClass = parseSig(sig, container);
 200             } catch (IllegalArgumentException ex) {
 201                 // support obsolete early jsr175 format class files
 202                 annotationClass = constPool.getClassAt(typeIndex);
 203             }
 204         } catch (NoClassDefFoundError e) {
 205             if (exceptionOnMissingAnnotationClass)
 206                 // note: at this point sig is "[unknown]" or VM-style
 207                 // name instead of a binary name
 208                 throw new TypeNotPresentException(sig, e);
 209             skipAnnotation(buf, false);
 210             return null;
 211         }
 212         catch (TypeNotPresentException e) {
 213             if (exceptionOnMissingAnnotationClass)
 214                 throw e;
 215             skipAnnotation(buf, false);
 216             return null;
 217         }
 218         AnnotationType type = null;
 219         try {
 220             type = AnnotationType.getInstance(annotationClass);
 221         } catch (IllegalArgumentException e) {
 222             skipAnnotation(buf, false);
 223             return null;
 224         }
 225 
 226         Map<String, Class> memberTypes = type.memberTypes();
 227         Map<String, Object> memberValues =
 228             new LinkedHashMap<String, Object>(type.memberDefaults());
 229 
 230         int numMembers = buf.getShort() & 0xFFFF;
 231         for (int i = 0; i < numMembers; i++) {
 232             int memberNameIndex = buf.getShort() & 0xFFFF;
 233             String memberName = constPool.getUTF8At(memberNameIndex);
 234             Class memberType = memberTypes.get(memberName);
 235 
 236             if (memberType == null) {
 237                 // Member is no longer present in annotation type; ignore it
 238                 skipMemberValue(buf);
 239             } else {
 240                 Object value = parseMemberValue(memberType, buf, constPool, container);
 241                 if (value instanceof AnnotationTypeMismatchExceptionProxy)
 242                     ((AnnotationTypeMismatchExceptionProxy) value).
 243                         setMember(type.members().get(memberName));
 244                 memberValues.put(memberName, value);
 245             }
 246         }
 247         return annotationForMap(annotationClass, memberValues);
 248     }
 249 
 250     /**
 251      * Returns an annotation of the given type backed by the given
 252      * member -> value map.
 253      */
 254     public static Annotation annotationForMap(
 255         Class type, Map<String, Object> memberValues)
 256     {
 257         return (Annotation) Proxy.newProxyInstance(
 258             type.getClassLoader(), new Class[] { type },
 259             new AnnotationInvocationHandler(type, memberValues));
 260     }
 261 
 262     /**
 263      * Parses the annotation member value at the current position in the
 264      * specified byte buffer, resolving constant references in the specified
 265      * constant pool.  The cursor of the byte buffer must point to a
 266      * "member_value structure" as described in the
 267      * RuntimeVisibleAnnotations_attribute:
 268      *
 269      *  member_value {
 270      *    u1 tag;
 271      *    union {
 272      *       u2   const_value_index;
 273      *       {
 274      *           u2   type_name_index;
 275      *           u2   const_name_index;
 276      *       } enum_const_value;
 277      *       u2   class_info_index;
 278      *       annotation annotation_value;
 279      *       {
 280      *           u2    num_values;
 281      *           member_value values[num_values];
 282      *       } array_value;
 283      *    } value;
 284      * }
 285      *
 286      * The member must be of the indicated type. If it is not, this
 287      * method returns an AnnotationTypeMismatchExceptionProxy.
 288      */
 289     public static Object parseMemberValue(Class memberType, ByteBuffer buf,

 290                                           ConstantPool constPool,
 291                                           Class container) {
 292         Object result = null;
 293         int tag = buf.get();
 294         switch(tag) {
 295           case 'e':
 296               return parseEnumValue(memberType, buf, constPool, container);
 297           case 'c':
 298               result = parseClassValue(buf, constPool, container);
 299               break;
 300           case '@':
 301               result = parseAnnotation(buf, constPool, container, true);
 302               break;
 303           case '[':
 304               return parseArray(memberType, buf, constPool, container);
 305           default:
 306               result = parseConst(tag, buf, constPool);
 307         }
 308 
 309         if (!(result instanceof ExceptionProxy) &&
 310             !memberType.isInstance(result))
 311             result = new AnnotationTypeMismatchExceptionProxy(
 312                 result.getClass() + "[" + result + "]");
 313         return result;
 314     }
 315 
 316     /**


 344           case 'Z':
 345             return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
 346           case 's':
 347             return constPool.getUTF8At(constIndex);
 348           default:
 349             throw new AnnotationFormatError(
 350                 "Invalid member-value tag in annotation: " + tag);
 351         }
 352     }
 353 
 354     /**
 355      * Parses the Class member value at the current position in the
 356      * specified byte buffer, resolving constant references in the specified
 357      * constant pool.  The cursor of the byte buffer must point to a "class
 358      * info index" as described in the RuntimeVisibleAnnotations_attribute:
 359      *
 360      *       u2   class_info_index;
 361      */
 362     private static Object parseClassValue(ByteBuffer buf,
 363                                           ConstantPool constPool,
 364                                           Class container) {
 365         int classIndex = buf.getShort() & 0xFFFF;
 366         try {
 367             try {
 368                 String sig = constPool.getUTF8At(classIndex);
 369                 return parseSig(sig, container);
 370             } catch (IllegalArgumentException ex) {
 371                 // support obsolete early jsr175 format class files
 372                 return constPool.getClassAt(classIndex);
 373             }
 374         } catch (NoClassDefFoundError e) {
 375             return new TypeNotPresentExceptionProxy("[unknown]", e);
 376         }
 377         catch (TypeNotPresentException e) {
 378             return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
 379         }
 380     }
 381 
 382     private static Class<?> parseSig(String sig, Class container) {
 383         if (sig.equals("V")) return void.class;
 384         SignatureParser parser = SignatureParser.make();
 385         TypeSignature typeSig = parser.parseTypeSig(sig);
 386         GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
 387         Reifier reify = Reifier.make(factory);
 388         typeSig.accept(reify);
 389         Type result = reify.getResult();
 390         return toClass(result);
 391     }
 392     static Class toClass(Type o) {
 393         if (o instanceof GenericArrayType)
 394             return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
 395                                      0)
 396                 .getClass();
 397         return (Class)o;
 398     }
 399 
 400     /**
 401      * Parses the enum constant member value at the current position in the
 402      * specified byte buffer, resolving constant references in the specified
 403      * constant pool.  The cursor of the byte buffer must point to a
 404      * "enum_const_value structure" as described in the
 405      * RuntimeVisibleAnnotations_attribute:
 406      *
 407      *       {
 408      *           u2   type_name_index;
 409      *           u2   const_name_index;
 410      *       } enum_const_value;
 411      */
 412     private static Object parseEnumValue(Class enumType, ByteBuffer buf,
 413                                          ConstantPool constPool,
 414                                          Class container) {
 415         int typeNameIndex = buf.getShort() & 0xFFFF;
 416         String typeName  = constPool.getUTF8At(typeNameIndex);
 417         int constNameIndex = buf.getShort() & 0xFFFF;
 418         String constName = constPool.getUTF8At(constNameIndex);
 419 
 420         if (!typeName.endsWith(";")) {
 421             // support now-obsolete early jsr175-format class files.
 422             if (!enumType.getName().equals(typeName))
 423             return new AnnotationTypeMismatchExceptionProxy(
 424                 typeName + "." + constName);
 425         } else if (enumType != parseSig(typeName, container)) {
 426             return new AnnotationTypeMismatchExceptionProxy(
 427                 typeName + "." + constName);
 428         }
 429 
 430         try {
 431             return  Enum.valueOf(enumType, constName);
 432         } catch(IllegalArgumentException e) {
 433             return new EnumConstantNotPresentExceptionProxy(
 434                 (Class<? extends Enum>)enumType, constName);
 435         }
 436     }
 437 
 438     /**
 439      * Parses the array value at the current position in the specified byte
 440      * buffer, resolving constant references in the specified constant pool.
 441      * The cursor of the byte buffer must point to an array value struct
 442      * as specified in the RuntimeVisibleAnnotations_attribute:
 443      *
 444      *       {
 445      *           u2    num_values;
 446      *           member_value values[num_values];
 447      *       } array_value;
 448      *
 449      * If the array values do not match arrayType, an
 450      * AnnotationTypeMismatchExceptionProxy will be returned.
 451      */
 452     private static Object parseArray(Class arrayType,
 453                                      ByteBuffer buf,
 454                                      ConstantPool constPool,
 455                                      Class container) {
 456         int length = buf.getShort() & 0xFFFF;  // Number of array components
 457         Class componentType = arrayType.getComponentType();
 458 
 459         if (componentType == byte.class) {
 460             return parseByteArray(length, buf, constPool);
 461         } else if (componentType == char.class) {
 462             return parseCharArray(length, buf, constPool);
 463         } else if (componentType == double.class) {
 464             return parseDoubleArray(length, buf, constPool);
 465         } else if (componentType == float.class) {
 466             return parseFloatArray(length, buf, constPool);
 467         } else if (componentType == int.class) {
 468             return parseIntArray(length, buf, constPool);
 469         } else if (componentType == long.class) {
 470             return parseLongArray(length, buf, constPool);
 471         } else if (componentType == short.class) {
 472             return parseShortArray(length, buf, constPool);
 473         } else if (componentType == boolean.class) {
 474             return parseBooleanArray(length, buf, constPool);
 475         } else if (componentType == String.class) {
 476             return parseStringArray(length, buf, constPool);
 477         } else if (componentType == Class.class) {
 478             return parseClassArray(length, buf, constPool, container);
 479         } else if (componentType.isEnum()) {
 480             return parseEnumArray(length, componentType, buf,
 481                                   constPool, container);
 482         } else {
 483             assert componentType.isAnnotation();
 484             return parseAnnotationArray(length, componentType, buf,
 485                                         constPool, container);
 486         }
 487     }
 488 
 489     private static Object parseByteArray(int length,
 490                                   ByteBuffer buf, ConstantPool constPool) {
 491         byte[] result = new byte[length];
 492         boolean typeMismatch = false;
 493         int tag = 0;
 494 
 495         for (int i = 0; i < length; i++) {
 496             tag = buf.get();
 497             if (tag == 'B') {
 498                 int index = buf.getShort() & 0xFFFF;
 499                 result[i] = (byte) constPool.getIntAt(index);
 500             } else {
 501                 skipMemberValue(tag, buf);
 502                 typeMismatch = true;
 503             }
 504         }


 643         String[] result = new String[length];
 644         boolean typeMismatch = false;
 645         int tag = 0;
 646 
 647         for (int i = 0; i < length; i++) {
 648             tag = buf.get();
 649             if (tag == 's') {
 650                 int index = buf.getShort() & 0xFFFF;
 651                 result[i] = constPool.getUTF8At(index);
 652             } else {
 653                 skipMemberValue(tag, buf);
 654                 typeMismatch = true;
 655             }
 656         }
 657         return typeMismatch ? exceptionProxy(tag) : result;
 658     }
 659 
 660     private static Object parseClassArray(int length,
 661                                           ByteBuffer buf,
 662                                           ConstantPool constPool,
 663                                           Class container) {
 664         Object[] result = new Class[length];
 665         boolean typeMismatch = false;
 666         int tag = 0;
 667 
 668         for (int i = 0; i < length; i++) {
 669             tag = buf.get();
 670             if (tag == 'c') {
 671                 result[i] = parseClassValue(buf, constPool, container);
 672             } else {
 673                 skipMemberValue(tag, buf);
 674                 typeMismatch = true;
 675             }
 676         }
 677         return typeMismatch ? exceptionProxy(tag) : result;
 678     }
 679 
 680     private static Object parseEnumArray(int length, Class enumType,
 681                                          ByteBuffer buf,
 682                                          ConstantPool constPool,
 683                                          Class container) {
 684         Object[] result = (Object[]) Array.newInstance(enumType, length);
 685         boolean typeMismatch = false;
 686         int tag = 0;
 687 
 688         for (int i = 0; i < length; i++) {
 689             tag = buf.get();
 690             if (tag == 'e') {
 691                 result[i] = parseEnumValue(enumType, buf, constPool, container);
 692             } else {
 693                 skipMemberValue(tag, buf);
 694                 typeMismatch = true;
 695             }
 696         }
 697         return typeMismatch ? exceptionProxy(tag) : result;
 698     }
 699 
 700     private static Object parseAnnotationArray(int length,
 701                                                Class annotationType,
 702                                                ByteBuffer buf,
 703                                                ConstantPool constPool,
 704                                                Class container) {
 705         Object[] result = (Object[]) Array.newInstance(annotationType, length);
 706         boolean typeMismatch = false;
 707         int tag = 0;
 708 
 709         for (int i = 0; i < length; i++) {
 710             tag = buf.get();
 711             if (tag == '@') {
 712                 result[i] = parseAnnotation(buf, constPool, container, true);
 713             } else {
 714                 skipMemberValue(tag, buf);
 715                 typeMismatch = true;
 716             }
 717         }
 718         return typeMismatch ? exceptionProxy(tag) : result;
 719     }
 720 
 721     /**
 722      * Return an appropriate exception proxy for a mismatching array
 723      * annotation where the erroneous array has the specified tag.
 724      */


 780 
 781     /**
 782      * Skips the array value at the current position in the specified byte
 783      * buffer.  The cursor of the byte buffer must point to an array value
 784      * struct.
 785      */
 786     private static void skipArray(ByteBuffer buf) {
 787         int length = buf.getShort() & 0xFFFF;
 788         for (int i = 0; i < length; i++)
 789             skipMemberValue(buf);
 790     }
 791 
 792     /*
 793      * This method converts the annotation map returned by the parseAnnotations()
 794      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 795      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 796      * This avoids the reflection classes to load the Annotation class until
 797      * it is needed.
 798      */
 799     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 800     public static Annotation[] toArray(Map<Class, Annotation> annotations) {
 801         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 802     }
 803 }


  42 /**
  43  * Parser for Java programming language annotations.  Translates
  44  * annotation byte streams emitted by compiler into annotation objects.
  45  *
  46  * @author  Josh Bloch
  47  * @since   1.5
  48  */
  49 public class AnnotationParser {
  50     /**
  51      * Parses the annotations described by the specified byte array.
  52      * resolving constant references in the specified constant pool.
  53      * The array must contain an array of annotations as described
  54      * in the RuntimeVisibleAnnotations_attribute:
  55      *
  56      *   u2 num_annotations;
  57      *   annotation annotations[num_annotations];
  58      *
  59      * @throws AnnotationFormatError if an annotation is found to be
  60      *         malformed.
  61      */
  62     public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
  63                 byte[] rawAnnotations,
  64                 ConstantPool constPool,
  65                 Class<?> container) {
  66         if (rawAnnotations == null)
  67             return Collections.emptyMap();
  68 
  69         try {
  70             return parseAnnotations2(rawAnnotations, constPool, container);
  71         } catch(BufferUnderflowException e) {
  72             throw new AnnotationFormatError("Unexpected end of annotations.");
  73         } catch(IllegalArgumentException e) {
  74             // Type mismatch in constant pool
  75             throw new AnnotationFormatError(e);
  76         }
  77     }
  78 
  79     private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
  80                 byte[] rawAnnotations,
  81                 ConstantPool constPool,
  82                 Class<?> container) {
  83         Map<Class<? extends Annotation>, Annotation> result = 
  84             new LinkedHashMap<Class<? extends Annotation>, Annotation>();
  85         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
  86         int numAnnotations = buf.getShort() & 0xFFFF;
  87         for (int i = 0; i < numAnnotations; i++) {
  88             Annotation a = parseAnnotation(buf, constPool, container, false);
  89             if (a != null) {
  90                 Class<? extends Annotation> klass = a.annotationType();
  91                 AnnotationType type = AnnotationType.getInstance(klass);
  92                 if (type.retention() == RetentionPolicy.RUNTIME)
  93                     if (result.put(klass, a) != null)
  94                         throw new AnnotationFormatError(
  95                             "Duplicate annotation for class: "+klass+": " + a);
  96             }
  97         }
  98         return result;
  99     }
 100 
 101     /**
 102      * Parses the parameter annotations described by the specified byte array.
 103      * resolving constant references in the specified constant pool.
 104      * The array must contain an array of annotations as described
 105      * in the RuntimeVisibleParameterAnnotations_attribute:
 106      *
 107      *    u1 num_parameters;
 108      *    {
 109      *        u2 num_annotations;
 110      *        annotation annotations[num_annotations];
 111      *    } parameter_annotations[num_parameters];
 112      *
 113      * Unlike parseAnnotations, rawAnnotations must not be null!
 114      * A null value must be handled by the caller.  This is so because
 115      * we cannot determine the number of parameters if rawAnnotations
 116      * is null.  Also, the caller should check that the number
 117      * of parameters indicated by the return value of this method
 118      * matches the actual number of method parameters.  A mismatch
 119      * indicates that an AnnotationFormatError should be thrown.
 120      *
 121      * @throws AnnotationFormatError if an annotation is found to be
 122      *         malformed.
 123      */
 124     public static Annotation[][] parseParameterAnnotations(
 125                     byte[] rawAnnotations,
 126                     ConstantPool constPool,
 127                     Class<?> container) {
 128         try {
 129             return parseParameterAnnotations2(rawAnnotations, constPool, container);
 130         } catch(BufferUnderflowException e) {
 131             throw new AnnotationFormatError(
 132                 "Unexpected end of parameter annotations.");
 133         } catch(IllegalArgumentException e) {
 134             // Type mismatch in constant pool
 135             throw new AnnotationFormatError(e);
 136         }
 137     }
 138 
 139     private static Annotation[][] parseParameterAnnotations2(
 140                     byte[] rawAnnotations,
 141                     ConstantPool constPool,
 142                     Class<?> container) {
 143         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
 144         int numParameters = buf.get() & 0xFF;
 145         Annotation[][] result = new Annotation[numParameters][];
 146 
 147         for (int i = 0; i < numParameters; i++) {
 148             int numAnnotations = buf.getShort() & 0xFFFF;
 149             List<Annotation> annotations =
 150                 new ArrayList<Annotation>(numAnnotations);
 151             for (int j = 0; j < numAnnotations; j++) {
 152                 Annotation a = parseAnnotation(buf, constPool, container, false);
 153                 if (a != null) {
 154                     AnnotationType type = AnnotationType.getInstance(
 155                                               a.annotationType());
 156                     if (type.retention() == RetentionPolicy.RUNTIME)
 157                         annotations.add(a);
 158                 }
 159             }
 160             result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
 161         }
 162         return result;


 172      * structure" as described in the RuntimeVisibleAnnotations_attribute:
 173      *
 174      * annotation {
 175      *    u2    type_index;
 176      *       u2    num_member_value_pairs;
 177      *       {    u2    member_name_index;
 178      *             member_value value;
 179      *       }    member_value_pairs[num_member_value_pairs];
 180      *    }
 181      * }
 182      *
 183      * Returns the annotation, or null if the annotation's type cannot
 184      * be found by the VM, or is not a valid annotation type.
 185      *
 186      * @param exceptionOnMissingAnnotationClass if true, throw
 187      * TypeNotPresentException if a referenced annotation type is not
 188      * available at runtime
 189      */
 190     private static Annotation parseAnnotation(ByteBuffer buf,
 191                                               ConstantPool constPool,
 192                                               Class<?> container,
 193                                               boolean exceptionOnMissingAnnotationClass) {
 194         int typeIndex = buf.getShort() & 0xFFFF;
 195         Class<? extends Annotation> annotationClass = null;
 196         String sig = "[unknown]";
 197         try {
 198             try {
 199                 sig = constPool.getUTF8At(typeIndex);
 200                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
 201             } catch (IllegalArgumentException ex) {
 202                 // support obsolete early jsr175 format class files
 203                 annotationClass = constPool.getClassAt(typeIndex);
 204             }
 205         } catch (NoClassDefFoundError e) {
 206             if (exceptionOnMissingAnnotationClass)
 207                 // note: at this point sig is "[unknown]" or VM-style
 208                 // name instead of a binary name
 209                 throw new TypeNotPresentException(sig, e);
 210             skipAnnotation(buf, false);
 211             return null;
 212         }
 213         catch (TypeNotPresentException e) {
 214             if (exceptionOnMissingAnnotationClass)
 215                 throw e;
 216             skipAnnotation(buf, false);
 217             return null;
 218         }
 219         AnnotationType type = null;
 220         try {
 221             type = AnnotationType.getInstance(annotationClass);
 222         } catch (IllegalArgumentException e) {
 223             skipAnnotation(buf, false);
 224             return null;
 225         }
 226 
 227         Map<String, Class<?>> memberTypes = type.memberTypes();
 228         Map<String, Object> memberValues =
 229             new LinkedHashMap<String, Object>(type.memberDefaults());
 230 
 231         int numMembers = buf.getShort() & 0xFFFF;
 232         for (int i = 0; i < numMembers; i++) {
 233             int memberNameIndex = buf.getShort() & 0xFFFF;
 234             String memberName = constPool.getUTF8At(memberNameIndex);
 235             Class<?> memberType = memberTypes.get(memberName);
 236 
 237             if (memberType == null) {
 238                 // Member is no longer present in annotation type; ignore it
 239                 skipMemberValue(buf);
 240             } else {
 241                 Object value = parseMemberValue(memberType, buf, constPool, container);
 242                 if (value instanceof AnnotationTypeMismatchExceptionProxy)
 243                     ((AnnotationTypeMismatchExceptionProxy) value).
 244                         setMember(type.members().get(memberName));
 245                 memberValues.put(memberName, value);
 246             }
 247         }
 248         return annotationForMap(annotationClass, memberValues);
 249     }
 250 
 251     /**
 252      * Returns an annotation of the given type backed by the given
 253      * member -> value map.
 254      */
 255     public static Annotation annotationForMap(
 256         Class<? extends Annotation> type, Map<String, Object> memberValues)
 257     {
 258         return (Annotation) Proxy.newProxyInstance(
 259             type.getClassLoader(), new Class[] { type },
 260             new AnnotationInvocationHandler(type, memberValues));
 261     }
 262 
 263     /**
 264      * Parses the annotation member value at the current position in the
 265      * specified byte buffer, resolving constant references in the specified
 266      * constant pool.  The cursor of the byte buffer must point to a
 267      * "member_value structure" as described in the
 268      * RuntimeVisibleAnnotations_attribute:
 269      *
 270      *  member_value {
 271      *    u1 tag;
 272      *    union {
 273      *       u2   const_value_index;
 274      *       {
 275      *           u2   type_name_index;
 276      *           u2   const_name_index;
 277      *       } enum_const_value;
 278      *       u2   class_info_index;
 279      *       annotation annotation_value;
 280      *       {
 281      *           u2    num_values;
 282      *           member_value values[num_values];
 283      *       } array_value;
 284      *    } value;
 285      * }
 286      *
 287      * The member must be of the indicated type. If it is not, this
 288      * method returns an AnnotationTypeMismatchExceptionProxy.
 289      */
 290     public static Object parseMemberValue(Class<?> memberType,
 291                                           ByteBuffer buf,
 292                                           ConstantPool constPool,
 293                                           Class<?> container) {
 294         Object result = null;
 295         int tag = buf.get();
 296         switch(tag) {
 297           case 'e':
 298               return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
 299           case 'c':
 300               result = parseClassValue(buf, constPool, container);
 301               break;
 302           case '@':
 303               result = parseAnnotation(buf, constPool, container, true);
 304               break;
 305           case '[':
 306               return parseArray(memberType, buf, constPool, container);
 307           default:
 308               result = parseConst(tag, buf, constPool);
 309         }
 310 
 311         if (!(result instanceof ExceptionProxy) &&
 312             !memberType.isInstance(result))
 313             result = new AnnotationTypeMismatchExceptionProxy(
 314                 result.getClass() + "[" + result + "]");
 315         return result;
 316     }
 317 
 318     /**


 346           case 'Z':
 347             return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
 348           case 's':
 349             return constPool.getUTF8At(constIndex);
 350           default:
 351             throw new AnnotationFormatError(
 352                 "Invalid member-value tag in annotation: " + tag);
 353         }
 354     }
 355 
 356     /**
 357      * Parses the Class member value at the current position in the
 358      * specified byte buffer, resolving constant references in the specified
 359      * constant pool.  The cursor of the byte buffer must point to a "class
 360      * info index" as described in the RuntimeVisibleAnnotations_attribute:
 361      *
 362      *       u2   class_info_index;
 363      */
 364     private static Object parseClassValue(ByteBuffer buf,
 365                                           ConstantPool constPool,
 366                                           Class<?> container) {
 367         int classIndex = buf.getShort() & 0xFFFF;
 368         try {
 369             try {
 370                 String sig = constPool.getUTF8At(classIndex);
 371                 return parseSig(sig, container);
 372             } catch (IllegalArgumentException ex) {
 373                 // support obsolete early jsr175 format class files
 374                 return constPool.getClassAt(classIndex);
 375             }
 376         } catch (NoClassDefFoundError e) {
 377             return new TypeNotPresentExceptionProxy("[unknown]", e);
 378         }
 379         catch (TypeNotPresentException e) {
 380             return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
 381         }
 382     }
 383 
 384     private static Class<?> parseSig(String sig, Class<?> container) {
 385         if (sig.equals("V")) return void.class;
 386         SignatureParser parser = SignatureParser.make();
 387         TypeSignature typeSig = parser.parseTypeSig(sig);
 388         GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
 389         Reifier reify = Reifier.make(factory);
 390         typeSig.accept(reify);
 391         Type result = reify.getResult();
 392         return toClass(result);
 393     }
 394     static Class<?> toClass(Type o) {
 395         if (o instanceof GenericArrayType)
 396             return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
 397                                      0)
 398                 .getClass();
 399         return (Class)o;
 400     }
 401 
 402     /**
 403      * Parses the enum constant member value at the current position in the
 404      * specified byte buffer, resolving constant references in the specified
 405      * constant pool.  The cursor of the byte buffer must point to a
 406      * "enum_const_value structure" as described in the
 407      * RuntimeVisibleAnnotations_attribute:
 408      *
 409      *       {
 410      *           u2   type_name_index;
 411      *           u2   const_name_index;
 412      *       } enum_const_value;
 413      */
 414     private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
 415                                          ConstantPool constPool,
 416                                          Class<?> container) {
 417         int typeNameIndex = buf.getShort() & 0xFFFF;
 418         String typeName  = constPool.getUTF8At(typeNameIndex);
 419         int constNameIndex = buf.getShort() & 0xFFFF;
 420         String constName = constPool.getUTF8At(constNameIndex);
 421 
 422         if (!typeName.endsWith(";")) {
 423             // support now-obsolete early jsr175-format class files.
 424             if (!enumType.getName().equals(typeName))
 425             return new AnnotationTypeMismatchExceptionProxy(
 426                 typeName + "." + constName);
 427         } else if (enumType != parseSig(typeName, container)) {
 428             return new AnnotationTypeMismatchExceptionProxy(
 429                 typeName + "." + constName);
 430         }
 431 
 432         try {
 433             return  Enum.valueOf(enumType, constName);
 434         } catch(IllegalArgumentException e) {
 435             return new EnumConstantNotPresentExceptionProxy(
 436                 (Class<? extends Enum>)enumType, constName);
 437         }
 438     }
 439 
 440     /**
 441      * Parses the array value at the current position in the specified byte
 442      * buffer, resolving constant references in the specified constant pool.
 443      * The cursor of the byte buffer must point to an array value struct
 444      * as specified in the RuntimeVisibleAnnotations_attribute:
 445      *
 446      *       {
 447      *           u2    num_values;
 448      *           member_value values[num_values];
 449      *       } array_value;
 450      *
 451      * If the array values do not match arrayType, an
 452      * AnnotationTypeMismatchExceptionProxy will be returned.
 453      */
 454     private static Object parseArray(Class<?> arrayType,
 455                                      ByteBuffer buf,
 456                                      ConstantPool constPool,
 457                                      Class<?> container) {
 458         int length = buf.getShort() & 0xFFFF;  // Number of array components
 459         Class<?> componentType = arrayType.getComponentType();
 460 
 461         if (componentType == byte.class) {
 462             return parseByteArray(length, buf, constPool);
 463         } else if (componentType == char.class) {
 464             return parseCharArray(length, buf, constPool);
 465         } else if (componentType == double.class) {
 466             return parseDoubleArray(length, buf, constPool);
 467         } else if (componentType == float.class) {
 468             return parseFloatArray(length, buf, constPool);
 469         } else if (componentType == int.class) {
 470             return parseIntArray(length, buf, constPool);
 471         } else if (componentType == long.class) {
 472             return parseLongArray(length, buf, constPool);
 473         } else if (componentType == short.class) {
 474             return parseShortArray(length, buf, constPool);
 475         } else if (componentType == boolean.class) {
 476             return parseBooleanArray(length, buf, constPool);
 477         } else if (componentType == String.class) {
 478             return parseStringArray(length, buf, constPool);
 479         } else if (componentType == Class.class) {
 480             return parseClassArray(length, buf, constPool, container);
 481         } else if (componentType.isEnum()) {
 482             return parseEnumArray(length, (Class<? extends Enum>)componentType, buf,
 483                                   constPool, container);
 484         } else {
 485             assert componentType.isAnnotation();
 486             return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,
 487                                         constPool, container);
 488         }
 489     }
 490 
 491     private static Object parseByteArray(int length,
 492                                   ByteBuffer buf, ConstantPool constPool) {
 493         byte[] result = new byte[length];
 494         boolean typeMismatch = false;
 495         int tag = 0;
 496 
 497         for (int i = 0; i < length; i++) {
 498             tag = buf.get();
 499             if (tag == 'B') {
 500                 int index = buf.getShort() & 0xFFFF;
 501                 result[i] = (byte) constPool.getIntAt(index);
 502             } else {
 503                 skipMemberValue(tag, buf);
 504                 typeMismatch = true;
 505             }
 506         }


 645         String[] result = new String[length];
 646         boolean typeMismatch = false;
 647         int tag = 0;
 648 
 649         for (int i = 0; i < length; i++) {
 650             tag = buf.get();
 651             if (tag == 's') {
 652                 int index = buf.getShort() & 0xFFFF;
 653                 result[i] = constPool.getUTF8At(index);
 654             } else {
 655                 skipMemberValue(tag, buf);
 656                 typeMismatch = true;
 657             }
 658         }
 659         return typeMismatch ? exceptionProxy(tag) : result;
 660     }
 661 
 662     private static Object parseClassArray(int length,
 663                                           ByteBuffer buf,
 664                                           ConstantPool constPool,
 665                                           Class<?> container) {
 666         Object[] result = new Class<?>[length];
 667         boolean typeMismatch = false;
 668         int tag = 0;
 669 
 670         for (int i = 0; i < length; i++) {
 671             tag = buf.get();
 672             if (tag == 'c') {
 673                 result[i] = parseClassValue(buf, constPool, container);
 674             } else {
 675                 skipMemberValue(tag, buf);
 676                 typeMismatch = true;
 677             }
 678         }
 679         return typeMismatch ? exceptionProxy(tag) : result;
 680     }
 681 
 682     private static Object parseEnumArray(int length, Class<? extends Enum> enumType,
 683                                          ByteBuffer buf,
 684                                          ConstantPool constPool,
 685                                          Class<?> container) {
 686         Object[] result = (Object[]) Array.newInstance(enumType, length);
 687         boolean typeMismatch = false;
 688         int tag = 0;
 689 
 690         for (int i = 0; i < length; i++) {
 691             tag = buf.get();
 692             if (tag == 'e') {
 693                 result[i] = parseEnumValue(enumType, buf, constPool, container);
 694             } else {
 695                 skipMemberValue(tag, buf);
 696                 typeMismatch = true;
 697             }
 698         }
 699         return typeMismatch ? exceptionProxy(tag) : result;
 700     }
 701 
 702     private static Object parseAnnotationArray(int length,
 703                                                Class<? extends Annotation> annotationType,
 704                                                ByteBuffer buf,
 705                                                ConstantPool constPool,
 706                                                Class<?> container) {
 707         Object[] result = (Object[]) Array.newInstance(annotationType, length);
 708         boolean typeMismatch = false;
 709         int tag = 0;
 710 
 711         for (int i = 0; i < length; i++) {
 712             tag = buf.get();
 713             if (tag == '@') {
 714                 result[i] = parseAnnotation(buf, constPool, container, true);
 715             } else {
 716                 skipMemberValue(tag, buf);
 717                 typeMismatch = true;
 718             }
 719         }
 720         return typeMismatch ? exceptionProxy(tag) : result;
 721     }
 722 
 723     /**
 724      * Return an appropriate exception proxy for a mismatching array
 725      * annotation where the erroneous array has the specified tag.
 726      */


 782 
 783     /**
 784      * Skips the array value at the current position in the specified byte
 785      * buffer.  The cursor of the byte buffer must point to an array value
 786      * struct.
 787      */
 788     private static void skipArray(ByteBuffer buf) {
 789         int length = buf.getShort() & 0xFFFF;
 790         for (int i = 0; i < length; i++)
 791             skipMemberValue(buf);
 792     }
 793 
 794     /*
 795      * This method converts the annotation map returned by the parseAnnotations()
 796      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 797      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 798      * This avoids the reflection classes to load the Annotation class until
 799      * it is needed.
 800      */
 801     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 802     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
 803         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 804     }
 805 }