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