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      */
parseAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class<?> container)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
parseSelectAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class<?> container, Class<? extends Annotation> ... selectAnnotationClasses)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 
parseAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class<?> container, Class<? extends Annotation>[] selectAnnotationClasses)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      */
parseParameterAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class<?> container)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 
parseParameterAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class<?> container)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      */
parseAnnotation(ByteBuffer buf, ConstantPool constPool, Class<?> container, boolean exceptionOnMissingAnnotationClass)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")
parseAnnotation2(ByteBuffer buf, ConstantPool constPool, Class<?> container, boolean exceptionOnMissingAnnotationClass, Class<? extends Annotation>[] selectAnnotationClasses)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 -> value map.
299      */
annotationForMap(final Class<? extends Annotation> type, final Map<String, Object> memberValues)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      * Return 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 }
870