2 * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
26 package sun.reflect.annotation;
28 import java.lang.annotation.*;
30 import java.nio.ByteBuffer;
31 import java.nio.BufferUnderflowException;
32 import java.lang.reflect.*;
33 import sun.reflect.ConstantPool;
35 import sun.reflect.generics.parser.SignatureFormatError;
36 import sun.reflect.generics.parser.SignatureParser;
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;
47 * Parser for Java programming language annotations. Translates
48 * annotation byte streams emitted by compiler into annotation objects.
53 public class AnnotationParser {
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:
61 * annotation annotations[num_annotations];
63 * @throws AnnotationFormatError if an annotation is found to be
66 public static Map<Class, Annotation> parseAnnotations(
67 byte[] rawAnnotations,
68 ConstantPool constPool,
70 if (rawAnnotations == null)
71 return Collections.emptyMap();
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);
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
88 public static Annotation[] parseAnnotationsIntoArray(
89 byte[] rawAnnotations,
90 ConstantPool constPool,
92 Map<Class, Annotation> annotations = parseAnnotations(rawAnnotations, constPool, container);
93 Annotation[] result = new Annotation[annotations.size()];
96 for (Annotation annotation : annotations.values()) {
97 result[i] = annotation;
104 private static Map<Class, Annotation> parseAnnotations2(
105 byte[] rawAnnotations,
106 ConstantPool constPool,
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);
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);
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:
133 * u2 num_annotations;
134 * annotation annotations[num_annotations];
135 * } parameter_annotations[num_parameters];
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.
145 * @throws AnnotationFormatError if an annotation is found to be
148 public static Annotation[][] parseParameterAnnotations(
149 byte[] rawAnnotations,
150 ConstantPool constPool,
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);
163 private static Annotation[][] parseParameterAnnotations2(
164 byte[] rawAnnotations,
165 ConstantPool constPool,
167 ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
168 int numParameters = buf.get() & 0xFF;
169 Annotation[][] result = new Annotation[numParameters][];
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);
178 AnnotationType type = AnnotationType.getInstance(
180 if (type.retention() == RetentionPolicy.RUNTIME)
184 result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
189 private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
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:
200 * u2 num_member_value_pairs;
201 * { u2 member_name_index;
202 * member_value value;
203 * } member_value_pairs[num_member_value_pairs];
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.
210 * @param exceptionOnMissingAnnotationClass if true, throw
211 * TypeNotPresentException if a referenced annotation type is not
212 * available at runtime
214 private static Annotation parseAnnotation(ByteBuffer buf,
215 ConstantPool constPool,
217 boolean exceptionOnMissingAnnotationClass) {
218 int typeIndex = buf.getShort() & 0xFFFF;
219 Class annotationClass = null;
220 String sig = "[unknown]";
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);
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);
237 catch (TypeNotPresentException e) {
238 if (exceptionOnMissingAnnotationClass)
240 skipAnnotation(buf, false);
243 AnnotationType type = null;
245 type = AnnotationType.getInstance(annotationClass);
246 } catch (IllegalArgumentException e) {
247 skipAnnotation(buf, false);
251 Map<String, Class> memberTypes = type.memberTypes();
252 Map<String, Object> memberValues =
253 new LinkedHashMap<String, Object>(type.memberDefaults());
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);
261 if (memberType == null) {
262 // Member is no longer present in annotation type; ignore it
263 skipMemberValue(buf);
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);
272 return annotationForMap(annotationClass, memberValues);
276 * Returns an annotation of the given type backed by the given
277 * member -> value map.
279 public static Annotation annotationForMap(
280 Class type, Map<String, Object> memberValues)
282 return (Annotation) Proxy.newProxyInstance(
283 type.getClassLoader(), new Class[] { type },
284 new AnnotationInvocationHandler(type, memberValues));
288 * Parses the annotation default value of the supplied method.
289 * This method is basically copied from
290 * java.lang.reflect.Method.getAnnotationDefault()
292 * @author Mathias Panzenböck
294 public static Object parseAnnotationDefault(Method method,
295 byte[] annotationDefault,
296 ConstantPool constPool,
298 if (annotationDefault == 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);
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:
320 * u2 const_value_index;
322 * u2 type_name_index;
323 * u2 const_name_index;
324 * } enum_const_value;
325 * u2 class_info_index;
326 * annotation annotation_value;
329 * member_value values[num_values];
334 * The member must be of the indicated type. If it is not, this
335 * method returns an AnnotationTypeMismatchExceptionProxy.
337 public static Object parseMemberValue(Class memberType, ByteBuffer buf,
338 ConstantPool constPool,
340 Object result = null;
344 return parseEnumValue(memberType, buf, constPool, container);
346 result = parseClassValue(buf, constPool, container);
349 result = parseAnnotation(buf, constPool, container, true);
352 return parseArray(memberType, buf, constPool, container);
354 result = parseConst(tag, buf, constPool);
357 if (!(result instanceof ExceptionProxy) &&
358 !memberType.isInstance(result))
359 result = new AnnotationTypeMismatchExceptionProxy(
360 result.getClass() + "[" + result + "]");
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:
372 * u2 const_value_index;
374 private static Object parseConst(int tag,
375 ByteBuffer buf, ConstantPool constPool) {
376 int constIndex = buf.getShort() & 0xFFFF;
379 return Byte.valueOf((byte) constPool.getIntAt(constIndex));
381 return Character.valueOf((char) constPool.getIntAt(constIndex));
383 return Double.valueOf(constPool.getDoubleAt(constIndex));
385 return Float.valueOf(constPool.getFloatAt(constIndex));
387 return Integer.valueOf(constPool.getIntAt(constIndex));
389 return Long.valueOf(constPool.getLongAt(constIndex));
391 return Short.valueOf((short) constPool.getIntAt(constIndex));
393 return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
395 return constPool.getUTF8At(constIndex);
397 throw new AnnotationFormatError(
398 "Invalid member-value tag in annotation: " + tag);
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:
408 * u2 class_info_index;
410 private static Object parseClassValue(ByteBuffer buf,
411 ConstantPool constPool,
413 int classIndex = buf.getShort() & 0xFFFF;
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);
422 } catch (NoClassDefFoundError e) {
423 return new TypeNotPresentExceptionProxy("[unknown]", e);
425 catch (TypeNotPresentException e) {
426 return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
430 private static Class<?> parseSig(String sig, Class container) {
432 return new SignatureParser(sig, container.getClassLoader()).getType();
434 catch(SignatureFormatError e) {
435 throw new AnnotationFormatError(
436 "Invalid type siganture in annotation: " + sig, e);
438 catch(ClassNotFoundException e) {
439 throw new AnnotationFormatError(
440 "Class described by this type siganture was not found: " + sig, e);
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);
455 static Class toClass(Type o) {
456 if (o instanceof GenericArrayType)
457 return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
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:
472 * u2 type_name_index;
473 * u2 const_name_index;
474 * } enum_const_value;
476 private static Object parseEnumValue(Class enumType, ByteBuffer buf,
477 ConstantPool constPool,
479 int typeNameIndex = buf.getShort() & 0xFFFF;
480 String typeName = constPool.getUTF8At(typeNameIndex);
481 int constNameIndex = buf.getShort() & 0xFFFF;
482 String constName = constPool.getUTF8At(constNameIndex);
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);
495 return Enum.valueOf(enumType, constName);
496 } catch(IllegalArgumentException e) {
497 return new EnumConstantNotPresentExceptionProxy(
498 (Class<? extends Enum>)enumType, constName);
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:
510 * member_value values[num_values];
513 * If the array values do not match arrayType, an
514 * AnnotationTypeMismatchExceptionProxy will be returned.
516 private static Object parseArray(Class arrayType,
518 ConstantPool constPool,
520 int length = buf.getShort() & 0xFFFF; // Number of array components
521 Class componentType = arrayType.getComponentType();
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);
547 assert componentType.isAnnotation();
548 return parseAnnotationArray(length, componentType, buf,
549 constPool, container);
553 private static Object parseByteArray(int length,
554 ByteBuffer buf, ConstantPool constPool) {
555 byte[] result = new byte[length];
556 boolean typeMismatch = false;
559 for (int i = 0; i < length; i++) {
562 int index = buf.getShort() & 0xFFFF;
563 result[i] = (byte) constPool.getIntAt(index);
565 skipMemberValue(tag, buf);
569 return typeMismatch ? exceptionProxy(tag) : result;
572 private static Object parseCharArray(int length,
573 ByteBuffer buf, ConstantPool constPool) {
574 char[] result = new char[length];
575 boolean typeMismatch = false;
578 for (int i = 0; i < length; i++) {
581 int index = buf.getShort() & 0xFFFF;
582 result[i] = (char) constPool.getIntAt(index);
584 skipMemberValue(tag, buf);
588 return typeMismatch ? exceptionProxy(tag) : result;
591 private static Object parseDoubleArray(int length,
592 ByteBuffer buf, ConstantPool constPool) {
593 double[] result = new double[length];
594 boolean typeMismatch = false;
597 for (int i = 0; i < length; i++) {
600 int index = buf.getShort() & 0xFFFF;
601 result[i] = constPool.getDoubleAt(index);
603 skipMemberValue(tag, buf);
607 return typeMismatch ? exceptionProxy(tag) : result;
610 private static Object parseFloatArray(int length,
611 ByteBuffer buf, ConstantPool constPool) {
612 float[] result = new float[length];
613 boolean typeMismatch = false;
616 for (int i = 0; i < length; i++) {
619 int index = buf.getShort() & 0xFFFF;
620 result[i] = constPool.getFloatAt(index);
622 skipMemberValue(tag, buf);
626 return typeMismatch ? exceptionProxy(tag) : result;
629 private static Object parseIntArray(int length,
630 ByteBuffer buf, ConstantPool constPool) {
631 int[] result = new int[length];
632 boolean typeMismatch = false;
635 for (int i = 0; i < length; i++) {
638 int index = buf.getShort() & 0xFFFF;
639 result[i] = constPool.getIntAt(index);
641 skipMemberValue(tag, buf);
645 return typeMismatch ? exceptionProxy(tag) : result;
648 private static Object parseLongArray(int length,
649 ByteBuffer buf, ConstantPool constPool) {
650 long[] result = new long[length];
651 boolean typeMismatch = false;
654 for (int i = 0; i < length; i++) {
657 int index = buf.getShort() & 0xFFFF;
658 result[i] = constPool.getLongAt(index);
660 skipMemberValue(tag, buf);
664 return typeMismatch ? exceptionProxy(tag) : result;
667 private static Object parseShortArray(int length,
668 ByteBuffer buf, ConstantPool constPool) {
669 short[] result = new short[length];
670 boolean typeMismatch = false;
673 for (int i = 0; i < length; i++) {
676 int index = buf.getShort() & 0xFFFF;
677 result[i] = (short) constPool.getIntAt(index);
679 skipMemberValue(tag, buf);
683 return typeMismatch ? exceptionProxy(tag) : result;
686 private static Object parseBooleanArray(int length,
687 ByteBuffer buf, ConstantPool constPool) {
688 boolean[] result = new boolean[length];
689 boolean typeMismatch = false;
692 for (int i = 0; i < length; i++) {
695 int index = buf.getShort() & 0xFFFF;
696 result[i] = (constPool.getIntAt(index) != 0);
698 skipMemberValue(tag, buf);
702 return typeMismatch ? exceptionProxy(tag) : result;
705 private static Object parseStringArray(int length,
706 ByteBuffer buf, ConstantPool constPool) {
707 String[] result = new String[length];
708 boolean typeMismatch = false;
711 for (int i = 0; i < length; i++) {
714 int index = buf.getShort() & 0xFFFF;
715 result[i] = constPool.getUTF8At(index);
717 skipMemberValue(tag, buf);
721 return typeMismatch ? exceptionProxy(tag) : result;
724 private static Object parseClassArray(int length,
726 ConstantPool constPool,
728 Object[] result = new Class[length];
729 boolean typeMismatch = false;
732 for (int i = 0; i < length; i++) {
735 result[i] = parseClassValue(buf, constPool, container);
737 skipMemberValue(tag, buf);
741 return typeMismatch ? exceptionProxy(tag) : result;
744 private static Object parseEnumArray(int length, Class enumType,
746 ConstantPool constPool,
748 Object[] result = (Object[]) Array.newInstance(enumType, length);
749 boolean typeMismatch = false;
752 for (int i = 0; i < length; i++) {
755 result[i] = parseEnumValue(enumType, buf, constPool, container);
757 skipMemberValue(tag, buf);
761 return typeMismatch ? exceptionProxy(tag) : result;
764 private static Object parseAnnotationArray(int length,
765 Class annotationType,
767 ConstantPool constPool,
769 Object[] result = (Object[]) Array.newInstance(annotationType, length);
770 boolean typeMismatch = false;
773 for (int i = 0; i < length; i++) {
776 result[i] = parseAnnotation(buf, constPool, container, true);
778 skipMemberValue(tag, buf);
782 return typeMismatch ? exceptionProxy(tag) : result;
786 * Return an appropriate exception proxy for a mismatching array
787 * annotation where the erroneous array has the specified tag.
789 private static ExceptionProxy exceptionProxy(int tag) {
790 return new AnnotationTypeMismatchExceptionProxy(
791 "Array with component tag: " + tag);
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).
800 * @parameter complete true if the byte buffer points to the beginning
801 * of an annotation structure (rather than two bytes in).
803 private static void skipAnnotation(ByteBuffer buf, boolean 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);
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."
818 private static void skipMemberValue(ByteBuffer buf) {
820 skipMemberValue(tag, buf);
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."
828 private static void skipMemberValue(int tag, ByteBuffer buf) {
830 case 'e': // Enum value
831 buf.getInt(); // (Two shorts, actually.)
834 skipAnnotation(buf, true);
840 // Class, primitive, or String
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
850 private static void skipArray(ByteBuffer buf) {
851 int length = buf.getShort() & 0xFFFF;
852 for (int i = 0; i < length; i++)
853 skipMemberValue(buf);