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