1 /*
   2  * Copyright 2003-2005 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any 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 sun.reflect.ConstantPool;
  34 
  35 import sun.reflect.generics.parser.SignatureParser;
  36 import sun.reflect.generics.tree.TypeSignature;
  37 import sun.reflect.generics.factory.GenericsFactory;
  38 import sun.reflect.generics.factory.CoreReflectionFactory;
  39 import sun.reflect.generics.visitor.Reifier;
  40 import sun.reflect.generics.scope.ClassScope;
  41 
  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;
 162     }
 163 
 164     private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
 165                     new Annotation[0];
 166 
 167     /**
 168      * Parses the annotation at the current position in the specified
 169      * byte buffer, resolving constant references in the specified constant
 170      * pool.  The cursor of the byte buffer must point to an "annotation
 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     /**
 317      * Parses the primitive or String annotation member value indicated by
 318      * the specified tag byte at the current position in the specified byte
 319      * buffer, resolving constant reference in the specified constant pool.
 320      * The cursor of the byte buffer must point to an annotation member value
 321      * of the type indicated by the specified tag, as described in the
 322      * RuntimeVisibleAnnotations_attribute:
 323      *
 324      *       u2   const_value_index;
 325      */
 326     private static Object parseConst(int tag,
 327                                      ByteBuffer buf, ConstantPool constPool) {
 328         int constIndex = buf.getShort() & 0xFFFF;
 329         switch(tag) {
 330           case 'B':
 331             return Byte.valueOf((byte) constPool.getIntAt(constIndex));
 332           case 'C':
 333             return Character.valueOf((char) constPool.getIntAt(constIndex));
 334           case 'D':
 335             return Double.valueOf(constPool.getDoubleAt(constIndex));
 336           case 'F':
 337             return Float.valueOf(constPool.getFloatAt(constIndex));
 338           case 'I':
 339             return Integer.valueOf(constPool.getIntAt(constIndex));
 340           case 'J':
 341             return Long.valueOf(constPool.getLongAt(constIndex));
 342           case 'S':
 343             return Short.valueOf((short) constPool.getIntAt(constIndex));
 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         }
 505         return typeMismatch ? exceptionProxy(tag) : result;
 506     }
 507 
 508     private static Object parseCharArray(int length,
 509                                   ByteBuffer buf, ConstantPool constPool) {
 510         char[] result = new char[length];
 511         boolean typeMismatch = false;
 512         byte tag = 0;
 513 
 514         for (int i = 0; i < length; i++) {
 515             tag = buf.get();
 516             if (tag == 'C') {
 517                 int index = buf.getShort() & 0xFFFF;
 518                 result[i] = (char) constPool.getIntAt(index);
 519             } else {
 520                 skipMemberValue(tag, buf);
 521                 typeMismatch = true;
 522             }
 523         }
 524         return typeMismatch ? exceptionProxy(tag) : result;
 525     }
 526 
 527     private static Object parseDoubleArray(int length,
 528                                     ByteBuffer buf, ConstantPool constPool) {
 529         double[] result = new  double[length];
 530         boolean typeMismatch = false;
 531         int tag = 0;
 532 
 533         for (int i = 0; i < length; i++) {
 534             tag = buf.get();
 535             if (tag == 'D') {
 536                 int index = buf.getShort() & 0xFFFF;
 537                 result[i] = constPool.getDoubleAt(index);
 538             } else {
 539                 skipMemberValue(tag, buf);
 540                 typeMismatch = true;
 541             }
 542         }
 543         return typeMismatch ? exceptionProxy(tag) : result;
 544     }
 545 
 546     private static Object parseFloatArray(int length,
 547                                    ByteBuffer buf, ConstantPool constPool) {
 548         float[] result = new float[length];
 549         boolean typeMismatch = false;
 550         int tag = 0;
 551 
 552         for (int i = 0; i < length; i++) {
 553             tag = buf.get();
 554             if (tag == 'F') {
 555                 int index = buf.getShort() & 0xFFFF;
 556                 result[i] = constPool.getFloatAt(index);
 557             } else {
 558                 skipMemberValue(tag, buf);
 559                 typeMismatch = true;
 560             }
 561         }
 562         return typeMismatch ? exceptionProxy(tag) : result;
 563     }
 564 
 565     private static Object parseIntArray(int length,
 566                                  ByteBuffer buf, ConstantPool constPool) {
 567         int[] result = new  int[length];
 568         boolean typeMismatch = false;
 569         int tag = 0;
 570 
 571         for (int i = 0; i < length; i++) {
 572             tag = buf.get();
 573             if (tag == 'I') {
 574                 int index = buf.getShort() & 0xFFFF;
 575                 result[i] = constPool.getIntAt(index);
 576             } else {
 577                 skipMemberValue(tag, buf);
 578                 typeMismatch = true;
 579             }
 580         }
 581         return typeMismatch ? exceptionProxy(tag) : result;
 582     }
 583 
 584     private static Object parseLongArray(int length,
 585                                   ByteBuffer buf, ConstantPool constPool) {
 586         long[] result = new long[length];
 587         boolean typeMismatch = false;
 588         int tag = 0;
 589 
 590         for (int i = 0; i < length; i++) {
 591             tag = buf.get();
 592             if (tag == 'J') {
 593                 int index = buf.getShort() & 0xFFFF;
 594                 result[i] = constPool.getLongAt(index);
 595             } else {
 596                 skipMemberValue(tag, buf);
 597                 typeMismatch = true;
 598             }
 599         }
 600         return typeMismatch ? exceptionProxy(tag) : result;
 601     }
 602 
 603     private static Object parseShortArray(int length,
 604                                    ByteBuffer buf, ConstantPool constPool) {
 605         short[] result = new short[length];
 606         boolean typeMismatch = false;
 607         int tag = 0;
 608 
 609         for (int i = 0; i < length; i++) {
 610             tag = buf.get();
 611             if (tag == 'S') {
 612                 int index = buf.getShort() & 0xFFFF;
 613                 result[i] = (short) constPool.getIntAt(index);
 614             } else {
 615                 skipMemberValue(tag, buf);
 616                 typeMismatch = true;
 617             }
 618         }
 619         return typeMismatch ? exceptionProxy(tag) : result;
 620     }
 621 
 622     private static Object parseBooleanArray(int length,
 623                                      ByteBuffer buf, ConstantPool constPool) {
 624         boolean[] result = new boolean[length];
 625         boolean typeMismatch = false;
 626         int tag = 0;
 627 
 628         for (int i = 0; i < length; i++) {
 629             tag = buf.get();
 630             if (tag == 'Z') {
 631                 int index = buf.getShort() & 0xFFFF;
 632                 result[i] = (constPool.getIntAt(index) != 0);
 633             } else {
 634                 skipMemberValue(tag, buf);
 635                 typeMismatch = true;
 636             }
 637         }
 638         return typeMismatch ? exceptionProxy(tag) : result;
 639     }
 640 
 641     private static Object parseStringArray(int length,
 642                                     ByteBuffer buf,  ConstantPool constPool) {
 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      */
 725     private static ExceptionProxy exceptionProxy(int tag) {
 726         return new AnnotationTypeMismatchExceptionProxy(
 727             "Array with component tag: " + tag);
 728     }
 729 
 730     /**
 731      * Skips the annotation at the current position in the specified
 732      * byte buffer.  The cursor of the byte buffer must point to
 733      * an "annotation structure" OR two bytes into an annotation
 734      * structure (i.e., after the type index).
 735      *
 736      * @parameter complete true if the byte buffer points to the beginning
 737      *     of an annotation structure (rather than two bytes in).
 738      */
 739     private static void skipAnnotation(ByteBuffer buf, boolean complete) {
 740         if (complete)
 741             buf.getShort();   // Skip type index
 742         int numMembers = buf.getShort() & 0xFFFF;
 743         for (int i = 0; i < numMembers; i++) {
 744             buf.getShort();   // Skip memberNameIndex
 745             skipMemberValue(buf);
 746         }
 747     }
 748 
 749     /**
 750      * Skips the annotation member value at the current position in the
 751      * specified byte buffer.  The cursor of the byte buffer must point to a
 752      * "member_value structure."
 753      */
 754     private static void skipMemberValue(ByteBuffer buf) {
 755         int tag = buf.get();
 756         skipMemberValue(tag, buf);
 757     }
 758 
 759     /**
 760      * Skips the annotation member value at the current position in the
 761      * specified byte buffer.  The cursor of the byte buffer must point
 762      * immediately after the tag in a "member_value structure."
 763      */
 764     private static void skipMemberValue(int tag, ByteBuffer buf) {
 765         switch(tag) {
 766           case 'e': // Enum value
 767             buf.getInt();  // (Two shorts, actually.)
 768             break;
 769           case '@':
 770             skipAnnotation(buf, true);
 771             break;
 772           case '[':
 773             skipArray(buf);
 774             break;
 775           default:
 776             // Class, primitive, or String
 777             buf.getShort();
 778         }
 779     }
 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 }