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