1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.reflect.annotation;
  27 
  28 import java.lang.annotation.*;
  29 import java.util.*;
  30 import java.nio.ByteBuffer;
  31 import java.nio.BufferUnderflowException;
  32 import java.lang.reflect.*;
  33 import java.security.AccessController;
  34 import java.security.PrivilegedAction;
  35 import sun.reflect.ConstantPool;
  36 
  37 import sun.reflect.generics.parser.SignatureParser;
  38 import sun.reflect.generics.tree.TypeSignature;
  39 import sun.reflect.generics.factory.GenericsFactory;
  40 import sun.reflect.generics.factory.CoreReflectionFactory;
  41 import sun.reflect.generics.visitor.Reifier;
  42 import sun.reflect.generics.scope.ClassScope;
  43 
  44 /**
  45  * Parser for Java programming language annotations.  Translates
  46  * annotation byte streams emitted by compiler into annotation objects.
  47  *
  48  * @author  Josh Bloch
  49  * @since   1.5
  50  */
  51 public class AnnotationParser {
  52     /**
  53      * Parses the annotations described by the specified byte array.
  54      * resolving constant references in the specified constant pool.
  55      * The array must contain an array of annotations as described
  56      * in the RuntimeVisibleAnnotations_attribute:
  57      *
  58      *   u2 num_annotations;
  59      *   annotation annotations[num_annotations];
  60      *
  61      * @throws AnnotationFormatError if an annotation is found to be
  62      *         malformed.
  63      */
  64     public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
  65                 byte[] rawAnnotations,
  66                 ConstantPool constPool,
  67                 Class<?> container) {
  68         if (rawAnnotations == null)
  69             return Collections.emptyMap();
  70 
  71         try {
  72             return parseAnnotations2(rawAnnotations, constPool, container);
  73         } catch(BufferUnderflowException e) {
  74             throw new AnnotationFormatError("Unexpected end of annotations.");
  75         } catch(IllegalArgumentException e) {
  76             // Type mismatch in constant pool
  77             throw new AnnotationFormatError(e);
  78         }
  79     }
  80 
  81     private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
  82                 byte[] rawAnnotations,
  83                 ConstantPool constPool,
  84                 Class<?> container) {
  85         Map<Class<? extends Annotation>, Annotation> result =
  86             new LinkedHashMap<Class<? extends Annotation>, Annotation>();
  87         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
  88         int numAnnotations = buf.getShort() & 0xFFFF;
  89         for (int i = 0; i < numAnnotations; i++) {
  90             Annotation a = parseAnnotation(buf, constPool, container, false);
  91             if (a != null) {
  92                 Class<? extends Annotation> klass = a.annotationType();
  93                 AnnotationType type = AnnotationType.getInstance(klass);
  94                 if (type.retention() == RetentionPolicy.RUNTIME)
  95                     if (result.put(klass, a) != null)
  96                         throw new AnnotationFormatError(
  97                             "Duplicate annotation for class: "+klass+": " + a);
  98             }
  99         }
 100         return result;
 101     }
 102 
 103     /**
 104      * Parses the parameter annotations described by the specified byte array.
 105      * resolving constant references in the specified constant pool.
 106      * The array must contain an array of annotations as described
 107      * in the RuntimeVisibleParameterAnnotations_attribute:
 108      *
 109      *    u1 num_parameters;
 110      *    {
 111      *        u2 num_annotations;
 112      *        annotation annotations[num_annotations];
 113      *    } parameter_annotations[num_parameters];
 114      *
 115      * Unlike parseAnnotations, rawAnnotations must not be null!
 116      * A null value must be handled by the caller.  This is so because
 117      * we cannot determine the number of parameters if rawAnnotations
 118      * is null.  Also, the caller should check that the number
 119      * of parameters indicated by the return value of this method
 120      * matches the actual number of method parameters.  A mismatch
 121      * indicates that an AnnotationFormatError should be thrown.
 122      *
 123      * @throws AnnotationFormatError if an annotation is found to be
 124      *         malformed.
 125      */
 126     public static Annotation[][] parseParameterAnnotations(
 127                     byte[] rawAnnotations,
 128                     ConstantPool constPool,
 129                     Class<?> container) {
 130         try {
 131             return parseParameterAnnotations2(rawAnnotations, constPool, container);
 132         } catch(BufferUnderflowException e) {
 133             throw new AnnotationFormatError(
 134                 "Unexpected end of parameter annotations.");
 135         } catch(IllegalArgumentException e) {
 136             // Type mismatch in constant pool
 137             throw new AnnotationFormatError(e);
 138         }
 139     }
 140 
 141     private static Annotation[][] parseParameterAnnotations2(
 142                     byte[] rawAnnotations,
 143                     ConstantPool constPool,
 144                     Class<?> container) {
 145         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
 146         int numParameters = buf.get() & 0xFF;
 147         Annotation[][] result = new Annotation[numParameters][];
 148 
 149         for (int i = 0; i < numParameters; i++) {
 150             int numAnnotations = buf.getShort() & 0xFFFF;
 151             List<Annotation> annotations =
 152                 new ArrayList<Annotation>(numAnnotations);
 153             for (int j = 0; j < numAnnotations; j++) {
 154                 Annotation a = parseAnnotation(buf, constPool, container, false);
 155                 if (a != null) {
 156                     AnnotationType type = AnnotationType.getInstance(
 157                                               a.annotationType());
 158                     if (type.retention() == RetentionPolicy.RUNTIME)
 159                         annotations.add(a);
 160                 }
 161             }
 162             result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
 163         }
 164         return result;
 165     }
 166 
 167     private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
 168                     new Annotation[0];
 169 
 170     /**
 171      * Parses the annotation at the current position in the specified
 172      * byte buffer, resolving constant references in the specified constant
 173      * pool.  The cursor of the byte buffer must point to an "annotation
 174      * structure" as described in the RuntimeVisibleAnnotations_attribute:
 175      *
 176      * annotation {
 177      *    u2    type_index;
 178      *       u2    num_member_value_pairs;
 179      *       {    u2    member_name_index;
 180      *             member_value value;
 181      *       }    member_value_pairs[num_member_value_pairs];
 182      *    }
 183      * }
 184      *
 185      * Returns the annotation, or null if the annotation's type cannot
 186      * be found by the VM, or is not a valid annotation type.
 187      *
 188      * @param exceptionOnMissingAnnotationClass if true, throw
 189      * TypeNotPresentException if a referenced annotation type is not
 190      * available at runtime
 191      */
 192     @SuppressWarnings("unchecked")
 193     static Annotation parseAnnotation(ByteBuffer buf,
 194                                               ConstantPool constPool,
 195                                               Class<?> container,
 196                                               boolean exceptionOnMissingAnnotationClass) {
 197         int typeIndex = buf.getShort() & 0xFFFF;
 198         Class<? extends Annotation> annotationClass = null;
 199         String sig = "[unknown]";
 200         try {
 201             try {
 202                 sig = constPool.getUTF8At(typeIndex);
 203                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
 204             } catch (IllegalArgumentException ex) {
 205                 // support obsolete early jsr175 format class files
 206                 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
 207             }
 208         } catch (NoClassDefFoundError e) {
 209             if (exceptionOnMissingAnnotationClass)
 210                 // note: at this point sig is "[unknown]" or VM-style
 211                 // name instead of a binary name
 212                 throw new TypeNotPresentException(sig, e);
 213             skipAnnotation(buf, false);
 214             return null;
 215         }
 216         catch (TypeNotPresentException e) {
 217             if (exceptionOnMissingAnnotationClass)
 218                 throw e;
 219             skipAnnotation(buf, false);
 220             return null;
 221         }
 222         AnnotationType type = null;
 223         try {
 224             type = AnnotationType.getInstance(annotationClass);
 225         } catch (IllegalArgumentException e) {
 226             skipAnnotation(buf, false);
 227             return null;
 228         }
 229 
 230         Map<String, Class<?>> memberTypes = type.memberTypes();
 231         Map<String, Object> memberValues =
 232             new LinkedHashMap<String, Object>(type.memberDefaults());
 233 
 234         int numMembers = buf.getShort() & 0xFFFF;
 235         for (int i = 0; i < numMembers; i++) {
 236             int memberNameIndex = buf.getShort() & 0xFFFF;
 237             String memberName = constPool.getUTF8At(memberNameIndex);
 238             Class<?> memberType = memberTypes.get(memberName);
 239 
 240             if (memberType == null) {
 241                 // Member is no longer present in annotation type; ignore it
 242                 skipMemberValue(buf);
 243             } else {
 244                 Object value = parseMemberValue(memberType, buf, constPool, container);
 245                 if (value instanceof AnnotationTypeMismatchExceptionProxy)
 246                     ((AnnotationTypeMismatchExceptionProxy) value).
 247                         setMember(type.members().get(memberName));
 248                 memberValues.put(memberName, value);
 249             }
 250         }
 251         return annotationForMap(annotationClass, memberValues);
 252     }
 253 
 254     /**
 255      * Returns an annotation of the given type backed by the given
 256      * member -> value map.
 257      */
 258     public static Annotation annotationForMap(final Class<? extends Annotation> type,
 259                                               final Map<String, Object> memberValues)
 260     {
 261         return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
 262             public Annotation run() {
 263                 return (Annotation) Proxy.newProxyInstance(
 264                     type.getClassLoader(), new Class<?>[] { type },
 265                     new AnnotationInvocationHandler(type, memberValues));
 266             }});
 267     }
 268 
 269     /**
 270      * Parses the annotation member value at the current position in the
 271      * specified byte buffer, resolving constant references in the specified
 272      * constant pool.  The cursor of the byte buffer must point to a
 273      * "member_value structure" as described in the
 274      * RuntimeVisibleAnnotations_attribute:
 275      *
 276      *  member_value {
 277      *    u1 tag;
 278      *    union {
 279      *       u2   const_value_index;
 280      *       {
 281      *           u2   type_name_index;
 282      *           u2   const_name_index;
 283      *       } enum_const_value;
 284      *       u2   class_info_index;
 285      *       annotation annotation_value;
 286      *       {
 287      *           u2    num_values;
 288      *           member_value values[num_values];
 289      *       } array_value;
 290      *    } value;
 291      * }
 292      *
 293      * The member must be of the indicated type. If it is not, this
 294      * method returns an AnnotationTypeMismatchExceptionProxy.
 295      */
 296     @SuppressWarnings("unchecked")
 297     public static Object parseMemberValue(Class<?> memberType,
 298                                           ByteBuffer buf,
 299                                           ConstantPool constPool,
 300                                           Class<?> container) {
 301         Object result = null;
 302         int tag = buf.get();
 303         switch(tag) {
 304           case 'e':
 305               return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
 306           case 'c':
 307               result = parseClassValue(buf, constPool, container);
 308               break;
 309           case '@':
 310               result = parseAnnotation(buf, constPool, container, true);
 311               break;
 312           case '[':
 313               return parseArray(memberType, buf, constPool, container);
 314           default:
 315               result = parseConst(tag, buf, constPool);
 316         }
 317 
 318         if (!(result instanceof ExceptionProxy) &&
 319             !memberType.isInstance(result))
 320             result = new AnnotationTypeMismatchExceptionProxy(
 321                 result.getClass() + "[" + result + "]");
 322         return result;
 323     }
 324 
 325     /**
 326      * Parses the primitive or String annotation member value indicated by
 327      * the specified tag byte at the current position in the specified byte
 328      * buffer, resolving constant reference in the specified constant pool.
 329      * The cursor of the byte buffer must point to an annotation member value
 330      * of the type indicated by the specified tag, as described in the
 331      * RuntimeVisibleAnnotations_attribute:
 332      *
 333      *       u2   const_value_index;
 334      */
 335     private static Object parseConst(int tag,
 336                                      ByteBuffer buf, ConstantPool constPool) {
 337         int constIndex = buf.getShort() & 0xFFFF;
 338         switch(tag) {
 339           case 'B':
 340             return Byte.valueOf((byte) constPool.getIntAt(constIndex));
 341           case 'C':
 342             return Character.valueOf((char) constPool.getIntAt(constIndex));
 343           case 'D':
 344             return Double.valueOf(constPool.getDoubleAt(constIndex));
 345           case 'F':
 346             return Float.valueOf(constPool.getFloatAt(constIndex));
 347           case 'I':
 348             return Integer.valueOf(constPool.getIntAt(constIndex));
 349           case 'J':
 350             return Long.valueOf(constPool.getLongAt(constIndex));
 351           case 'S':
 352             return Short.valueOf((short) constPool.getIntAt(constIndex));
 353           case 'Z':
 354             return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
 355           case 's':
 356             return constPool.getUTF8At(constIndex);
 357           default:
 358             throw new AnnotationFormatError(
 359                 "Invalid member-value tag in annotation: " + tag);
 360         }
 361     }
 362 
 363     /**
 364      * Parses the Class member value at the current position in the
 365      * specified byte buffer, resolving constant references in the specified
 366      * constant pool.  The cursor of the byte buffer must point to a "class
 367      * info index" as described in the RuntimeVisibleAnnotations_attribute:
 368      *
 369      *       u2   class_info_index;
 370      */
 371     private static Object parseClassValue(ByteBuffer buf,
 372                                           ConstantPool constPool,
 373                                           Class<?> container) {
 374         int classIndex = buf.getShort() & 0xFFFF;
 375         try {
 376             try {
 377                 String sig = constPool.getUTF8At(classIndex);
 378                 return parseSig(sig, container);
 379             } catch (IllegalArgumentException ex) {
 380                 // support obsolete early jsr175 format class files
 381                 return constPool.getClassAt(classIndex);
 382             }
 383         } catch (NoClassDefFoundError e) {
 384             return new TypeNotPresentExceptionProxy("[unknown]", e);
 385         }
 386         catch (TypeNotPresentException e) {
 387             return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
 388         }
 389     }
 390 
 391     private static Class<?> parseSig(String sig, Class<?> container) {
 392         if (sig.equals("V")) return void.class;
 393         SignatureParser parser = SignatureParser.make();
 394         TypeSignature typeSig = parser.parseTypeSig(sig);
 395         GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
 396         Reifier reify = Reifier.make(factory);
 397         typeSig.accept(reify);
 398         Type result = reify.getResult();
 399         return toClass(result);
 400     }
 401     static Class<?> toClass(Type o) {
 402         if (o instanceof GenericArrayType)
 403             return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
 404                                      0)
 405                 .getClass();
 406         return (Class)o;
 407     }
 408 
 409     /**
 410      * Parses the enum constant member value at the current position in the
 411      * specified byte buffer, resolving constant references in the specified
 412      * constant pool.  The cursor of the byte buffer must point to a
 413      * "enum_const_value structure" as described in the
 414      * RuntimeVisibleAnnotations_attribute:
 415      *
 416      *       {
 417      *           u2   type_name_index;
 418      *           u2   const_name_index;
 419      *       } enum_const_value;
 420      */
 421     @SuppressWarnings({"rawtypes", "unchecked"})
 422     private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
 423                                          ConstantPool constPool,
 424                                          Class<?> container) {
 425         int typeNameIndex = buf.getShort() & 0xFFFF;
 426         String typeName  = constPool.getUTF8At(typeNameIndex);
 427         int constNameIndex = buf.getShort() & 0xFFFF;
 428         String constName = constPool.getUTF8At(constNameIndex);
 429 
 430         if (!typeName.endsWith(";")) {
 431             // support now-obsolete early jsr175-format class files.
 432             if (!enumType.getName().equals(typeName))
 433             return new AnnotationTypeMismatchExceptionProxy(
 434                 typeName + "." + constName);
 435         } else if (enumType != parseSig(typeName, container)) {
 436             return new AnnotationTypeMismatchExceptionProxy(
 437                 typeName + "." + constName);
 438         }
 439 
 440         try {
 441             return  Enum.valueOf(enumType, constName);
 442         } catch(IllegalArgumentException e) {
 443             return new EnumConstantNotPresentExceptionProxy(
 444                 (Class<? extends Enum<?>>)enumType, constName);
 445         }
 446     }
 447 
 448     /**
 449      * Parses the array value at the current position in the specified byte
 450      * buffer, resolving constant references in the specified constant pool.
 451      * The cursor of the byte buffer must point to an array value struct
 452      * as specified in the RuntimeVisibleAnnotations_attribute:
 453      *
 454      *       {
 455      *           u2    num_values;
 456      *           member_value values[num_values];
 457      *       } array_value;
 458      *
 459      * If the array values do not match arrayType, an
 460      * AnnotationTypeMismatchExceptionProxy will be returned.
 461      */
 462     @SuppressWarnings("unchecked")
 463     private static Object parseArray(Class<?> arrayType,
 464                                      ByteBuffer buf,
 465                                      ConstantPool constPool,
 466                                      Class<?> container) {
 467         int length = buf.getShort() & 0xFFFF;  // Number of array components
 468         Class<?> componentType = arrayType.getComponentType();
 469 
 470         if (componentType == byte.class) {
 471             return parseByteArray(length, buf, constPool);
 472         } else if (componentType == char.class) {
 473             return parseCharArray(length, buf, constPool);
 474         } else if (componentType == double.class) {
 475             return parseDoubleArray(length, buf, constPool);
 476         } else if (componentType == float.class) {
 477             return parseFloatArray(length, buf, constPool);
 478         } else if (componentType == int.class) {
 479             return parseIntArray(length, buf, constPool);
 480         } else if (componentType == long.class) {
 481             return parseLongArray(length, buf, constPool);
 482         } else if (componentType == short.class) {
 483             return parseShortArray(length, buf, constPool);
 484         } else if (componentType == boolean.class) {
 485             return parseBooleanArray(length, buf, constPool);
 486         } else if (componentType == String.class) {
 487             return parseStringArray(length, buf, constPool);
 488         } else if (componentType == Class.class) {
 489             return parseClassArray(length, buf, constPool, container);
 490         } else if (componentType.isEnum()) {
 491             return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf,
 492                                   constPool, container);
 493         } else {
 494             assert componentType.isAnnotation();
 495             return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,
 496                                         constPool, container);
 497         }
 498     }
 499 
 500     private static Object parseByteArray(int length,
 501                                   ByteBuffer buf, ConstantPool constPool) {
 502         byte[] result = new byte[length];
 503         boolean typeMismatch = false;
 504         int tag = 0;
 505 
 506         for (int i = 0; i < length; i++) {
 507             tag = buf.get();
 508             if (tag == 'B') {
 509                 int index = buf.getShort() & 0xFFFF;
 510                 result[i] = (byte) constPool.getIntAt(index);
 511             } else {
 512                 skipMemberValue(tag, buf);
 513                 typeMismatch = true;
 514             }
 515         }
 516         return typeMismatch ? exceptionProxy(tag) : result;
 517     }
 518 
 519     private static Object parseCharArray(int length,
 520                                   ByteBuffer buf, ConstantPool constPool) {
 521         char[] result = new char[length];
 522         boolean typeMismatch = false;
 523         byte tag = 0;
 524 
 525         for (int i = 0; i < length; i++) {
 526             tag = buf.get();
 527             if (tag == 'C') {
 528                 int index = buf.getShort() & 0xFFFF;
 529                 result[i] = (char) constPool.getIntAt(index);
 530             } else {
 531                 skipMemberValue(tag, buf);
 532                 typeMismatch = true;
 533             }
 534         }
 535         return typeMismatch ? exceptionProxy(tag) : result;
 536     }
 537 
 538     private static Object parseDoubleArray(int length,
 539                                     ByteBuffer buf, ConstantPool constPool) {
 540         double[] result = new  double[length];
 541         boolean typeMismatch = false;
 542         int tag = 0;
 543 
 544         for (int i = 0; i < length; i++) {
 545             tag = buf.get();
 546             if (tag == 'D') {
 547                 int index = buf.getShort() & 0xFFFF;
 548                 result[i] = constPool.getDoubleAt(index);
 549             } else {
 550                 skipMemberValue(tag, buf);
 551                 typeMismatch = true;
 552             }
 553         }
 554         return typeMismatch ? exceptionProxy(tag) : result;
 555     }
 556 
 557     private static Object parseFloatArray(int length,
 558                                    ByteBuffer buf, ConstantPool constPool) {
 559         float[] result = new float[length];
 560         boolean typeMismatch = false;
 561         int tag = 0;
 562 
 563         for (int i = 0; i < length; i++) {
 564             tag = buf.get();
 565             if (tag == 'F') {
 566                 int index = buf.getShort() & 0xFFFF;
 567                 result[i] = constPool.getFloatAt(index);
 568             } else {
 569                 skipMemberValue(tag, buf);
 570                 typeMismatch = true;
 571             }
 572         }
 573         return typeMismatch ? exceptionProxy(tag) : result;
 574     }
 575 
 576     private static Object parseIntArray(int length,
 577                                  ByteBuffer buf, ConstantPool constPool) {
 578         int[] result = new  int[length];
 579         boolean typeMismatch = false;
 580         int tag = 0;
 581 
 582         for (int i = 0; i < length; i++) {
 583             tag = buf.get();
 584             if (tag == 'I') {
 585                 int index = buf.getShort() & 0xFFFF;
 586                 result[i] = constPool.getIntAt(index);
 587             } else {
 588                 skipMemberValue(tag, buf);
 589                 typeMismatch = true;
 590             }
 591         }
 592         return typeMismatch ? exceptionProxy(tag) : result;
 593     }
 594 
 595     private static Object parseLongArray(int length,
 596                                   ByteBuffer buf, ConstantPool constPool) {
 597         long[] result = new long[length];
 598         boolean typeMismatch = false;
 599         int tag = 0;
 600 
 601         for (int i = 0; i < length; i++) {
 602             tag = buf.get();
 603             if (tag == 'J') {
 604                 int index = buf.getShort() & 0xFFFF;
 605                 result[i] = constPool.getLongAt(index);
 606             } else {
 607                 skipMemberValue(tag, buf);
 608                 typeMismatch = true;
 609             }
 610         }
 611         return typeMismatch ? exceptionProxy(tag) : result;
 612     }
 613 
 614     private static Object parseShortArray(int length,
 615                                    ByteBuffer buf, ConstantPool constPool) {
 616         short[] result = new short[length];
 617         boolean typeMismatch = false;
 618         int tag = 0;
 619 
 620         for (int i = 0; i < length; i++) {
 621             tag = buf.get();
 622             if (tag == 'S') {
 623                 int index = buf.getShort() & 0xFFFF;
 624                 result[i] = (short) constPool.getIntAt(index);
 625             } else {
 626                 skipMemberValue(tag, buf);
 627                 typeMismatch = true;
 628             }
 629         }
 630         return typeMismatch ? exceptionProxy(tag) : result;
 631     }
 632 
 633     private static Object parseBooleanArray(int length,
 634                                      ByteBuffer buf, ConstantPool constPool) {
 635         boolean[] result = new boolean[length];
 636         boolean typeMismatch = false;
 637         int tag = 0;
 638 
 639         for (int i = 0; i < length; i++) {
 640             tag = buf.get();
 641             if (tag == 'Z') {
 642                 int index = buf.getShort() & 0xFFFF;
 643                 result[i] = (constPool.getIntAt(index) != 0);
 644             } else {
 645                 skipMemberValue(tag, buf);
 646                 typeMismatch = true;
 647             }
 648         }
 649         return typeMismatch ? exceptionProxy(tag) : result;
 650     }
 651 
 652     private static Object parseStringArray(int length,
 653                                     ByteBuffer buf,  ConstantPool constPool) {
 654         String[] result = new String[length];
 655         boolean typeMismatch = false;
 656         int tag = 0;
 657 
 658         for (int i = 0; i < length; i++) {
 659             tag = buf.get();
 660             if (tag == 's') {
 661                 int index = buf.getShort() & 0xFFFF;
 662                 result[i] = constPool.getUTF8At(index);
 663             } else {
 664                 skipMemberValue(tag, buf);
 665                 typeMismatch = true;
 666             }
 667         }
 668         return typeMismatch ? exceptionProxy(tag) : result;
 669     }
 670 
 671     private static Object parseClassArray(int length,
 672                                           ByteBuffer buf,
 673                                           ConstantPool constPool,
 674                                           Class<?> container) {
 675         Object[] result = new Class<?>[length];
 676         boolean typeMismatch = false;
 677         int tag = 0;
 678 
 679         for (int i = 0; i < length; i++) {
 680             tag = buf.get();
 681             if (tag == 'c') {
 682                 result[i] = parseClassValue(buf, constPool, container);
 683             } else {
 684                 skipMemberValue(tag, buf);
 685                 typeMismatch = true;
 686             }
 687         }
 688         return typeMismatch ? exceptionProxy(tag) : result;
 689     }
 690 
 691     private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType,
 692                                          ByteBuffer buf,
 693                                          ConstantPool constPool,
 694                                          Class<?> container) {
 695         Object[] result = (Object[]) Array.newInstance(enumType, length);
 696         boolean typeMismatch = false;
 697         int tag = 0;
 698 
 699         for (int i = 0; i < length; i++) {
 700             tag = buf.get();
 701             if (tag == 'e') {
 702                 result[i] = parseEnumValue(enumType, buf, constPool, container);
 703             } else {
 704                 skipMemberValue(tag, buf);
 705                 typeMismatch = true;
 706             }
 707         }
 708         return typeMismatch ? exceptionProxy(tag) : result;
 709     }
 710 
 711     private static Object parseAnnotationArray(int length,
 712                                                Class<? extends Annotation> annotationType,
 713                                                ByteBuffer buf,
 714                                                ConstantPool constPool,
 715                                                Class<?> container) {
 716         Object[] result = (Object[]) Array.newInstance(annotationType, length);
 717         boolean typeMismatch = false;
 718         int tag = 0;
 719 
 720         for (int i = 0; i < length; i++) {
 721             tag = buf.get();
 722             if (tag == '@') {
 723                 result[i] = parseAnnotation(buf, constPool, container, true);
 724             } else {
 725                 skipMemberValue(tag, buf);
 726                 typeMismatch = true;
 727             }
 728         }
 729         return typeMismatch ? exceptionProxy(tag) : result;
 730     }
 731 
 732     /**
 733      * Return an appropriate exception proxy for a mismatching array
 734      * annotation where the erroneous array has the specified tag.
 735      */
 736     private static ExceptionProxy exceptionProxy(int tag) {
 737         return new AnnotationTypeMismatchExceptionProxy(
 738             "Array with component tag: " + tag);
 739     }
 740 
 741     /**
 742      * Skips the annotation at the current position in the specified
 743      * byte buffer.  The cursor of the byte buffer must point to
 744      * an "annotation structure" OR two bytes into an annotation
 745      * structure (i.e., after the type index).
 746      *
 747      * @parameter complete true if the byte buffer points to the beginning
 748      *     of an annotation structure (rather than two bytes in).
 749      */
 750     private static void skipAnnotation(ByteBuffer buf, boolean complete) {
 751         if (complete)
 752             buf.getShort();   // Skip type index
 753         int numMembers = buf.getShort() & 0xFFFF;
 754         for (int i = 0; i < numMembers; i++) {
 755             buf.getShort();   // Skip memberNameIndex
 756             skipMemberValue(buf);
 757         }
 758     }
 759 
 760     /**
 761      * Skips the annotation member value at the current position in the
 762      * specified byte buffer.  The cursor of the byte buffer must point to a
 763      * "member_value structure."
 764      */
 765     private static void skipMemberValue(ByteBuffer buf) {
 766         int tag = buf.get();
 767         skipMemberValue(tag, buf);
 768     }
 769 
 770     /**
 771      * Skips the annotation member value at the current position in the
 772      * specified byte buffer.  The cursor of the byte buffer must point
 773      * immediately after the tag in a "member_value structure."
 774      */
 775     private static void skipMemberValue(int tag, ByteBuffer buf) {
 776         switch(tag) {
 777           case 'e': // Enum value
 778             buf.getInt();  // (Two shorts, actually.)
 779             break;
 780           case '@':
 781             skipAnnotation(buf, true);
 782             break;
 783           case '[':
 784             skipArray(buf);
 785             break;
 786           default:
 787             // Class, primitive, or String
 788             buf.getShort();
 789         }
 790     }
 791 
 792     /**
 793      * Skips the array value at the current position in the specified byte
 794      * buffer.  The cursor of the byte buffer must point to an array value
 795      * struct.
 796      */
 797     private static void skipArray(ByteBuffer buf) {
 798         int length = buf.getShort() & 0xFFFF;
 799         for (int i = 0; i < length; i++)
 800             skipMemberValue(buf);
 801     }
 802 
 803     /*
 804      * This method converts the annotation map returned by the parseAnnotations()
 805      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 806      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 807      * This avoids the reflection classes to load the Annotation class until
 808      * it is needed.
 809      */
 810     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 811     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
 812         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 813     }
 814 
 815     static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
 816 }