History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/reflect/annotation/AnnotationParser.java (1 of 18352 files). Show all

Unified · Split

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