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