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 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     @SuppressWarnings("unchecked")
 191     static Annotation parseAnnotation(ByteBuffer buf,
 192                                               ConstantPool constPool,
 193                                               Class<?> container,
 194                                               boolean exceptionOnMissingAnnotationClass) {
 195         int typeIndex = buf.getShort() & 0xFFFF;
 196         Class<? extends Annotation> annotationClass = null;
 197         String sig = "[unknown]";
 198         try {
 199             try {
 200                 sig = constPool.getUTF8At(typeIndex);
 201                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
 202             } catch (IllegalArgumentException ex) {
 203                 // support obsolete early jsr175 format class files
 204                 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
 205             }
 206         } catch (NoClassDefFoundError e) {
 207             if (exceptionOnMissingAnnotationClass)
 208                 // note: at this point sig is "[unknown]" or VM-style
 209                 // name instead of a binary name
 210                 throw new TypeNotPresentException(sig, e);
 211             skipAnnotation(buf, false);
 212             return null;
 213         }
 214         catch (TypeNotPresentException e) {
 215             if (exceptionOnMissingAnnotationClass)
 216                 throw e;
 217             skipAnnotation(buf, false);
 218             return null;
 219         }
 220         AnnotationType type = null;
 221         try {
 222             type = AnnotationType.getInstance(annotationClass);
 223         } catch (IllegalArgumentException e) {
 224             skipAnnotation(buf, false);
 225             return null;
 226         }
 227 
 228         Map<String, Class<?>> memberTypes = type.memberTypes();
 229         Map<String, Object> memberValues =
 230             new LinkedHashMap<String, Object>(type.memberDefaults());
 231 
 232         int numMembers = buf.getShort() & 0xFFFF;
 233         for (int i = 0; i < numMembers; i++) {
 234             int memberNameIndex = buf.getShort() & 0xFFFF;
 235             String memberName = constPool.getUTF8At(memberNameIndex);
 236             Class<?> memberType = memberTypes.get(memberName);
 237 
 238             if (memberType == null) {
 239                 // Member is no longer present in annotation type; ignore it
 240                 skipMemberValue(buf);
 241             } else {
 242                 Object value = parseMemberValue(memberType, buf, constPool, container);
 243                 if (value instanceof AnnotationTypeMismatchExceptionProxy)
 244                     ((AnnotationTypeMismatchExceptionProxy) value).
 245                         setMember(type.members().get(memberName));
 246                 memberValues.put(memberName, value);
 247             }
 248         }
 249         return annotationForMap(annotationClass, memberValues);
 250     }
 251 
 252     /**
 253      * Returns an annotation of the given type backed by the given
 254      * member -> value map.
 255      */
 256     public static Annotation annotationForMap(
 257         Class<? extends Annotation> type, Map<String, Object> memberValues)
 258     {
 259         return (Annotation) Proxy.newProxyInstance(
 260             type.getClassLoader(), new Class<?>[] { type },
 261             new AnnotationInvocationHandler(type, memberValues));
 262     }
 263 
 264     /**
 265      * Parses the annotation member value at the current position in the
 266      * specified byte buffer, resolving constant references in the specified
 267      * constant pool.  The cursor of the byte buffer must point to a
 268      * "member_value structure" as described in the
 269      * RuntimeVisibleAnnotations_attribute:
 270      *
 271      *  member_value {
 272      *    u1 tag;
 273      *    union {
 274      *       u2   const_value_index;
 275      *       {
 276      *           u2   type_name_index;
 277      *           u2   const_name_index;
 278      *       } enum_const_value;
 279      *       u2   class_info_index;
 280      *       annotation annotation_value;
 281      *       {
 282      *           u2    num_values;
 283      *           member_value values[num_values];
 284      *       } array_value;
 285      *    } value;
 286      * }
 287      *
 288      * The member must be of the indicated type. If it is not, this
 289      * method returns an AnnotationTypeMismatchExceptionProxy.
 290      */
 291     @SuppressWarnings("unchecked")
 292     public static Object parseMemberValue(Class<?> memberType,
 293                                           ByteBuffer buf,
 294                                           ConstantPool constPool,
 295                                           Class<?> container) {
 296         Object result = null;
 297         int tag = buf.get();
 298         switch(tag) {
 299           case 'e':
 300               return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
 301           case 'c':
 302               result = parseClassValue(buf, constPool, container);
 303               break;
 304           case '@':
 305               result = parseAnnotation(buf, constPool, container, true);
 306               break;
 307           case '[':
 308               return parseArray(memberType, buf, constPool, container);
 309           default:
 310               result = parseConst(tag, buf, constPool);
 311         }
 312 
 313         if (!(result instanceof ExceptionProxy) &&
 314             !memberType.isInstance(result))
 315             result = new AnnotationTypeMismatchExceptionProxy(
 316                 result.getClass() + "[" + result + "]");
 317         return result;
 318     }
 319 
 320     /**
 321      * Parses the primitive or String annotation member value indicated by
 322      * the specified tag byte at the current position in the specified byte
 323      * buffer, resolving constant reference in the specified constant pool.
 324      * The cursor of the byte buffer must point to an annotation member value
 325      * of the type indicated by the specified tag, as described in the
 326      * RuntimeVisibleAnnotations_attribute:
 327      *
 328      *       u2   const_value_index;
 329      */
 330     private static Object parseConst(int tag,
 331                                      ByteBuffer buf, ConstantPool constPool) {
 332         int constIndex = buf.getShort() & 0xFFFF;
 333         switch(tag) {
 334           case 'B':
 335             return Byte.valueOf((byte) constPool.getIntAt(constIndex));
 336           case 'C':
 337             return Character.valueOf((char) constPool.getIntAt(constIndex));
 338           case 'D':
 339             return Double.valueOf(constPool.getDoubleAt(constIndex));
 340           case 'F':
 341             return Float.valueOf(constPool.getFloatAt(constIndex));
 342           case 'I':
 343             return Integer.valueOf(constPool.getIntAt(constIndex));
 344           case 'J':
 345             return Long.valueOf(constPool.getLongAt(constIndex));
 346           case 'S':
 347             return Short.valueOf((short) constPool.getIntAt(constIndex));
 348           case 'Z':
 349             return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
 350           case 's':
 351             return constPool.getUTF8At(constIndex);
 352           default:
 353             throw new AnnotationFormatError(
 354                 "Invalid member-value tag in annotation: " + tag);
 355         }
 356     }
 357 
 358     /**
 359      * Parses the Class member value at the current position in the
 360      * specified byte buffer, resolving constant references in the specified
 361      * constant pool.  The cursor of the byte buffer must point to a "class
 362      * info index" as described in the RuntimeVisibleAnnotations_attribute:
 363      *
 364      *       u2   class_info_index;
 365      */
 366     private static Object parseClassValue(ByteBuffer buf,
 367                                           ConstantPool constPool,
 368                                           Class<?> container) {
 369         int classIndex = buf.getShort() & 0xFFFF;
 370         try {
 371             try {
 372                 String sig = constPool.getUTF8At(classIndex);
 373                 return parseSig(sig, container);
 374             } catch (IllegalArgumentException ex) {
 375                 // support obsolete early jsr175 format class files
 376                 return constPool.getClassAt(classIndex);
 377             }
 378         } catch (NoClassDefFoundError e) {
 379             return new TypeNotPresentExceptionProxy("[unknown]", e);
 380         }
 381         catch (TypeNotPresentException e) {
 382             return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
 383         }
 384     }
 385 
 386     private static Class<?> parseSig(String sig, Class<?> container) {
 387         if (sig.equals("V")) return void.class;
 388         SignatureParser parser = SignatureParser.make();
 389         TypeSignature typeSig = parser.parseTypeSig(sig);
 390         GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
 391         Reifier reify = Reifier.make(factory);
 392         typeSig.accept(reify);
 393         Type result = reify.getResult();
 394         return toClass(result);
 395     }
 396     static Class<?> toClass(Type o) {
 397         if (o instanceof GenericArrayType)
 398             return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
 399                                      0)
 400                 .getClass();
 401         return (Class)o;
 402     }
 403 
 404     /**
 405      * Parses the enum constant member value at the current position in the
 406      * specified byte buffer, resolving constant references in the specified
 407      * constant pool.  The cursor of the byte buffer must point to a
 408      * "enum_const_value structure" as described in the
 409      * RuntimeVisibleAnnotations_attribute:
 410      *
 411      *       {
 412      *           u2   type_name_index;
 413      *           u2   const_name_index;
 414      *       } enum_const_value;
 415      */
 416     @SuppressWarnings({"rawtypes", "unchecked"})
 417     private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
 418                                          ConstantPool constPool,
 419                                          Class<?> container) {
 420         int typeNameIndex = buf.getShort() & 0xFFFF;
 421         String typeName  = constPool.getUTF8At(typeNameIndex);
 422         int constNameIndex = buf.getShort() & 0xFFFF;
 423         String constName = constPool.getUTF8At(constNameIndex);
 424 
 425         if (!typeName.endsWith(";")) {
 426             // support now-obsolete early jsr175-format class files.
 427             if (!enumType.getName().equals(typeName))
 428             return new AnnotationTypeMismatchExceptionProxy(
 429                 typeName + "." + constName);
 430         } else if (enumType != parseSig(typeName, container)) {
 431             return new AnnotationTypeMismatchExceptionProxy(
 432                 typeName + "." + constName);
 433         }
 434 
 435         try {
 436             return  Enum.valueOf(enumType, constName);
 437         } catch(IllegalArgumentException e) {
 438             return new EnumConstantNotPresentExceptionProxy(
 439                 (Class<? extends Enum<?>>)enumType, constName);
 440         }
 441     }
 442 
 443     /**
 444      * Parses the array value at the current position in the specified byte
 445      * buffer, resolving constant references in the specified constant pool.
 446      * The cursor of the byte buffer must point to an array value struct
 447      * as specified in the RuntimeVisibleAnnotations_attribute:
 448      *
 449      *       {
 450      *           u2    num_values;
 451      *           member_value values[num_values];
 452      *       } array_value;
 453      *
 454      * If the array values do not match arrayType, an
 455      * AnnotationTypeMismatchExceptionProxy will be returned.
 456      */
 457     @SuppressWarnings("unchecked")
 458     private static Object parseArray(Class<?> arrayType,
 459                                      ByteBuffer buf,
 460                                      ConstantPool constPool,
 461                                      Class<?> container) {
 462         int length = buf.getShort() & 0xFFFF;  // Number of array components
 463         Class<?> componentType = arrayType.getComponentType();
 464 
 465         if (componentType == byte.class) {
 466             return parseByteArray(length, buf, constPool);
 467         } else if (componentType == char.class) {
 468             return parseCharArray(length, buf, constPool);
 469         } else if (componentType == double.class) {
 470             return parseDoubleArray(length, buf, constPool);
 471         } else if (componentType == float.class) {
 472             return parseFloatArray(length, buf, constPool);
 473         } else if (componentType == int.class) {
 474             return parseIntArray(length, buf, constPool);
 475         } else if (componentType == long.class) {
 476             return parseLongArray(length, buf, constPool);
 477         } else if (componentType == short.class) {
 478             return parseShortArray(length, buf, constPool);
 479         } else if (componentType == boolean.class) {
 480             return parseBooleanArray(length, buf, constPool);
 481         } else if (componentType == String.class) {
 482             return parseStringArray(length, buf, constPool);
 483         } else if (componentType == Class.class) {
 484             return parseClassArray(length, buf, constPool, container);
 485         } else if (componentType.isEnum()) {
 486             return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf,
 487                                   constPool, container);
 488         } else {
 489             assert componentType.isAnnotation();
 490             return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,
 491                                         constPool, container);
 492         }
 493     }
 494 
 495     private static Object parseByteArray(int length,
 496                                   ByteBuffer buf, ConstantPool constPool) {
 497         byte[] result = new byte[length];
 498         boolean typeMismatch = false;
 499         int tag = 0;
 500 
 501         for (int i = 0; i < length; i++) {
 502             tag = buf.get();
 503             if (tag == 'B') {
 504                 int index = buf.getShort() & 0xFFFF;
 505                 result[i] = (byte) constPool.getIntAt(index);
 506             } else {
 507                 skipMemberValue(tag, buf);
 508                 typeMismatch = true;
 509             }
 510         }
 511         return typeMismatch ? exceptionProxy(tag) : result;
 512     }
 513 
 514     private static Object parseCharArray(int length,
 515                                   ByteBuffer buf, ConstantPool constPool) {
 516         char[] result = new char[length];
 517         boolean typeMismatch = false;
 518         byte tag = 0;
 519 
 520         for (int i = 0; i < length; i++) {
 521             tag = buf.get();
 522             if (tag == 'C') {
 523                 int index = buf.getShort() & 0xFFFF;
 524                 result[i] = (char) constPool.getIntAt(index);
 525             } else {
 526                 skipMemberValue(tag, buf);
 527                 typeMismatch = true;
 528             }
 529         }
 530         return typeMismatch ? exceptionProxy(tag) : result;
 531     }
 532 
 533     private static Object parseDoubleArray(int length,
 534                                     ByteBuffer buf, ConstantPool constPool) {
 535         double[] result = new  double[length];
 536         boolean typeMismatch = false;
 537         int tag = 0;
 538 
 539         for (int i = 0; i < length; i++) {
 540             tag = buf.get();
 541             if (tag == 'D') {
 542                 int index = buf.getShort() & 0xFFFF;
 543                 result[i] = constPool.getDoubleAt(index);
 544             } else {
 545                 skipMemberValue(tag, buf);
 546                 typeMismatch = true;
 547             }
 548         }
 549         return typeMismatch ? exceptionProxy(tag) : result;
 550     }
 551 
 552     private static Object parseFloatArray(int length,
 553                                    ByteBuffer buf, ConstantPool constPool) {
 554         float[] result = new float[length];
 555         boolean typeMismatch = false;
 556         int tag = 0;
 557 
 558         for (int i = 0; i < length; i++) {
 559             tag = buf.get();
 560             if (tag == 'F') {
 561                 int index = buf.getShort() & 0xFFFF;
 562                 result[i] = constPool.getFloatAt(index);
 563             } else {
 564                 skipMemberValue(tag, buf);
 565                 typeMismatch = true;
 566             }
 567         }
 568         return typeMismatch ? exceptionProxy(tag) : result;
 569     }
 570 
 571     private static Object parseIntArray(int length,
 572                                  ByteBuffer buf, ConstantPool constPool) {
 573         int[] result = new  int[length];
 574         boolean typeMismatch = false;
 575         int tag = 0;
 576 
 577         for (int i = 0; i < length; i++) {
 578             tag = buf.get();
 579             if (tag == 'I') {
 580                 int index = buf.getShort() & 0xFFFF;
 581                 result[i] = constPool.getIntAt(index);
 582             } else {
 583                 skipMemberValue(tag, buf);
 584                 typeMismatch = true;
 585             }
 586         }
 587         return typeMismatch ? exceptionProxy(tag) : result;
 588     }
 589 
 590     private static Object parseLongArray(int length,
 591                                   ByteBuffer buf, ConstantPool constPool) {
 592         long[] result = new long[length];
 593         boolean typeMismatch = false;
 594         int tag = 0;
 595 
 596         for (int i = 0; i < length; i++) {
 597             tag = buf.get();
 598             if (tag == 'J') {
 599                 int index = buf.getShort() & 0xFFFF;
 600                 result[i] = constPool.getLongAt(index);
 601             } else {
 602                 skipMemberValue(tag, buf);
 603                 typeMismatch = true;
 604             }
 605         }
 606         return typeMismatch ? exceptionProxy(tag) : result;
 607     }
 608 
 609     private static Object parseShortArray(int length,
 610                                    ByteBuffer buf, ConstantPool constPool) {
 611         short[] result = new short[length];
 612         boolean typeMismatch = false;
 613         int tag = 0;
 614 
 615         for (int i = 0; i < length; i++) {
 616             tag = buf.get();
 617             if (tag == 'S') {
 618                 int index = buf.getShort() & 0xFFFF;
 619                 result[i] = (short) constPool.getIntAt(index);
 620             } else {
 621                 skipMemberValue(tag, buf);
 622                 typeMismatch = true;
 623             }
 624         }
 625         return typeMismatch ? exceptionProxy(tag) : result;
 626     }
 627 
 628     private static Object parseBooleanArray(int length,
 629                                      ByteBuffer buf, ConstantPool constPool) {
 630         boolean[] result = new boolean[length];
 631         boolean typeMismatch = false;
 632         int tag = 0;
 633 
 634         for (int i = 0; i < length; i++) {
 635             tag = buf.get();
 636             if (tag == 'Z') {
 637                 int index = buf.getShort() & 0xFFFF;
 638                 result[i] = (constPool.getIntAt(index) != 0);
 639             } else {
 640                 skipMemberValue(tag, buf);
 641                 typeMismatch = true;
 642             }
 643         }
 644         return typeMismatch ? exceptionProxy(tag) : result;
 645     }
 646 
 647     private static Object parseStringArray(int length,
 648                                     ByteBuffer buf,  ConstantPool constPool) {
 649         String[] result = new String[length];
 650         boolean typeMismatch = false;
 651         int tag = 0;
 652 
 653         for (int i = 0; i < length; i++) {
 654             tag = buf.get();
 655             if (tag == 's') {
 656                 int index = buf.getShort() & 0xFFFF;
 657                 result[i] = constPool.getUTF8At(index);
 658             } else {
 659                 skipMemberValue(tag, buf);
 660                 typeMismatch = true;
 661             }
 662         }
 663         return typeMismatch ? exceptionProxy(tag) : result;
 664     }
 665 
 666     private static Object parseClassArray(int length,
 667                                           ByteBuffer buf,
 668                                           ConstantPool constPool,
 669                                           Class<?> container) {
 670         Object[] result = new Class<?>[length];
 671         boolean typeMismatch = false;
 672         int tag = 0;
 673 
 674         for (int i = 0; i < length; i++) {
 675             tag = buf.get();
 676             if (tag == 'c') {
 677                 result[i] = parseClassValue(buf, constPool, container);
 678             } else {
 679                 skipMemberValue(tag, buf);
 680                 typeMismatch = true;
 681             }
 682         }
 683         return typeMismatch ? exceptionProxy(tag) : result;
 684     }
 685 
 686     private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType,
 687                                          ByteBuffer buf,
 688                                          ConstantPool constPool,
 689                                          Class<?> container) {
 690         Object[] result = (Object[]) Array.newInstance(enumType, length);
 691         boolean typeMismatch = false;
 692         int tag = 0;
 693 
 694         for (int i = 0; i < length; i++) {
 695             tag = buf.get();
 696             if (tag == 'e') {
 697                 result[i] = parseEnumValue(enumType, buf, constPool, container);
 698             } else {
 699                 skipMemberValue(tag, buf);
 700                 typeMismatch = true;
 701             }
 702         }
 703         return typeMismatch ? exceptionProxy(tag) : result;
 704     }
 705 
 706     private static Object parseAnnotationArray(int length,
 707                                                Class<? extends Annotation> annotationType,
 708                                                ByteBuffer buf,
 709                                                ConstantPool constPool,
 710                                                Class<?> container) {
 711         Object[] result = (Object[]) Array.newInstance(annotationType, length);
 712         boolean typeMismatch = false;
 713         int tag = 0;
 714 
 715         for (int i = 0; i < length; i++) {
 716             tag = buf.get();
 717             if (tag == '@') {
 718                 result[i] = parseAnnotation(buf, constPool, container, true);
 719             } else {
 720                 skipMemberValue(tag, buf);
 721                 typeMismatch = true;
 722             }
 723         }
 724         return typeMismatch ? exceptionProxy(tag) : result;
 725     }
 726 
 727     /**
 728      * Return an appropriate exception proxy for a mismatching array
 729      * annotation where the erroneous array has the specified tag.
 730      */
 731     private static ExceptionProxy exceptionProxy(int tag) {
 732         return new AnnotationTypeMismatchExceptionProxy(
 733             "Array with component tag: " + tag);
 734     }
 735 
 736     /**
 737      * Skips the annotation at the current position in the specified
 738      * byte buffer.  The cursor of the byte buffer must point to
 739      * an "annotation structure" OR two bytes into an annotation
 740      * structure (i.e., after the type index).
 741      *
 742      * @parameter complete true if the byte buffer points to the beginning
 743      *     of an annotation structure (rather than two bytes in).
 744      */
 745     private static void skipAnnotation(ByteBuffer buf, boolean complete) {
 746         if (complete)
 747             buf.getShort();   // Skip type index
 748         int numMembers = buf.getShort() & 0xFFFF;
 749         for (int i = 0; i < numMembers; i++) {
 750             buf.getShort();   // Skip memberNameIndex
 751             skipMemberValue(buf);
 752         }
 753     }
 754 
 755     /**
 756      * Skips the annotation member value at the current position in the
 757      * specified byte buffer.  The cursor of the byte buffer must point to a
 758      * "member_value structure."
 759      */
 760     private static void skipMemberValue(ByteBuffer buf) {
 761         int tag = buf.get();
 762         skipMemberValue(tag, buf);
 763     }
 764 
 765     /**
 766      * Skips the annotation member value at the current position in the
 767      * specified byte buffer.  The cursor of the byte buffer must point
 768      * immediately after the tag in a "member_value structure."
 769      */
 770     private static void skipMemberValue(int tag, ByteBuffer buf) {
 771         switch(tag) {
 772           case 'e': // Enum value
 773             buf.getInt();  // (Two shorts, actually.)
 774             break;
 775           case '@':
 776             skipAnnotation(buf, true);
 777             break;
 778           case '[':
 779             skipArray(buf);
 780             break;
 781           default:
 782             // Class, primitive, or String
 783             buf.getShort();
 784         }
 785     }
 786 
 787     /**
 788      * Skips the array value at the current position in the specified byte
 789      * buffer.  The cursor of the byte buffer must point to an array value
 790      * struct.
 791      */
 792     private static void skipArray(ByteBuffer buf) {
 793         int length = buf.getShort() & 0xFFFF;
 794         for (int i = 0; i < length; i++)
 795             skipMemberValue(buf);
 796     }
 797 
 798     /*
 799      * This method converts the annotation map returned by the parseAnnotations()
 800      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 801      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 802      * This avoids the reflection classes to load the Annotation class until
 803      * it is needed.
 804      */
 805     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 806     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
 807         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 808     }
 809 
 810     static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
 811 }