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