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