+++ /dev/null
-/*
- * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.reflect.annotation;
-
-import java.lang.annotation.*;
-import java.util.*;
-import java.nio.ByteBuffer;
-import java.nio.BufferUnderflowException;
-import java.lang.reflect.*;
-import sun.reflect.ConstantPool;
-
-import gnu.java.lang.reflect.FieldSignatureParser;
-
-
-/**
- * Parser for Java programming language annotations. Translates
- * annotation byte streams emitted by compiler into annotation objects.
- *
- * @author Josh Bloch
- * @since 1.5
- */
-public class AnnotationParser {
- /**
- * Parses the annotations described by the passed byte array,
- * but returns Annotation[] so I don't have to do this in C.
- *
- * @author Mathias Panzenböck
- *
- * @param rawAnnotations are the unparsed annotations
- * @param constPool is the constant pool of the declaring class
- * @param container is the containing class
- * @return the parsed annotations in an array
- * @throws AnnotationFormatError if an annotation is found to be
- * malformed.
- */
- public static Annotation[] parseAnnotationsIntoArray(
- byte[] rawAnnotations,
- ConstantPool constPool,
- Class container) {
- Map<Class, Annotation> annotations = parseAnnotations(rawAnnotations, constPool, container);
- return annotations.values().toArray(EMPTY_ANNOTATIONS_ARRAY);
- }
-
- /**
- * Parses parameter annotations.
- *
- * @author Mathias Panzenböck
- *
- * @param parameterAnnotations are the unparsed parameter annotations
- * @param constPool is the constant pool of the declaring class
- * @param container is the containing class
- * @return the parsed parameter annotations in an array 2 dimensional array
- * @throws AnnotationFormatError if an annotation is found to be
- * malformed.
- */
- public static Annotation[][] parseParameterAnnotations(
- byte[] parameterAnnotations,
- ConstantPool constPool,
- Class container,
- int numParameters) {
- if (parameterAnnotations == null)
- return new Annotation[numParameters][0];
-
- Annotation[][] result = parseParameterAnnotations(
- parameterAnnotations, constPool, container);
-
- if (result.length != numParameters)
- throw new AnnotationFormatError(
- "Parameter annotations don't match number of parameters (count was " +
- result.length + " but should be " + numParameters + ").");
- return result;
- }
-
- /**
- * Parses the annotation default value of the supplied method.
- * This method is basically copied from OpenJDKs
- * java.lang.reflect.Method.getAnnotationDefault()
- *
- * @author Mathias Panzenböck
- *
- * @param method represents the method for which the annotation default value has to be parsed
- * @param annotationDefault is the unparsed annotation default value
- * @param constPool is the constant pool of the declaring class
- * @return the parsed annotation default value (boxed, if it's a primitive type)
- * @throws AnnotationFormatError if an annotation is found to be
- * malformed.
- */
- public static Object parseAnnotationDefault(Method method,
- byte[] annotationDefault,
- ConstantPool constPool) {
- if (annotationDefault == null)
- return null;
-
- Class memberType = AnnotationType.invocationHandlerReturnType(
- method.getReturnType());
-
- Object result = AnnotationParser.parseMemberValue(
- memberType, ByteBuffer.wrap(annotationDefault),
- constPool, method.getDeclaringClass());
-
- if (result instanceof sun.reflect.annotation.ExceptionProxy)
- throw new AnnotationFormatError("Invalid default: " + method);
-
- return result;
- }
-
- /**
- * Parses the annotations described by the specified byte array.
- * resolving constant references in the specified constant pool.
- * The array must contain an array of annotations as described
- * in the RuntimeVisibleAnnotations_attribute:
- *
- * u2 num_annotations;
- * annotation annotations[num_annotations];
- *
- * @throws AnnotationFormatError if an annotation is found to be
- * malformed.
- */
- public static Map<Class, Annotation> parseAnnotations(
- byte[] rawAnnotations,
- ConstantPool constPool,
- Class container) {
- if (rawAnnotations == null)
- return Collections.emptyMap();
-
- try {
- return parseAnnotations2(rawAnnotations, constPool, container);
- } catch(BufferUnderflowException e) {
- throw new AnnotationFormatError("Unexpected end of annotations.");
- } catch(IllegalArgumentException e) {
- // Type mismatch in constant pool
- throw new AnnotationFormatError(e);
- }
- }
-
- private static Map<Class, Annotation> parseAnnotations2(
- byte[] rawAnnotations,
- ConstantPool constPool,
- Class container) {
- Map<Class, Annotation> result = new LinkedHashMap<Class, Annotation>();
- ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
- int numAnnotations = buf.getShort() & 0xFFFF;
- for (int i = 0; i < numAnnotations; i++) {
- Annotation a = parseAnnotation(buf, constPool, container, false);
- if (a != null) {
- Class klass = a.annotationType();
- AnnotationType type = AnnotationType.getInstance(klass);
- if (type.retention() == RetentionPolicy.RUNTIME)
- if (result.put(klass, a) != null)
- throw new AnnotationFormatError(
- "Duplicate annotation for class: "+klass+": " + a);
- }
- }
- return result;
- }
-
- /**
- * Parses the parameter annotations described by the specified byte array.
- * resolving constant references in the specified constant pool.
- * The array must contain an array of annotations as described
- * in the RuntimeVisibleParameterAnnotations_attribute:
- *
- * u1 num_parameters;
- * {
- * u2 num_annotations;
- * annotation annotations[num_annotations];
- * } parameter_annotations[num_parameters];
- *
- * Unlike parseAnnotations, rawAnnotations must not be null!
- * A null value must be handled by the caller. This is so because
- * we cannot determine the number of parameters if rawAnnotations
- * is null. Also, the caller should check that the number
- * of parameters indicated by the return value of this method
- * matches the actual number of method parameters. A mismatch
- * indicates that an AnnotationFormatError should be thrown.
- *
- * @throws AnnotationFormatError if an annotation is found to be
- * malformed.
- */
- public static Annotation[][] parseParameterAnnotations(
- byte[] rawAnnotations,
- ConstantPool constPool,
- Class container) {
- try {
- return parseParameterAnnotations2(rawAnnotations, constPool, container);
- } catch(BufferUnderflowException e) {
- throw new AnnotationFormatError(
- "Unexpected end of parameter annotations.");
- } catch(IllegalArgumentException e) {
- // Type mismatch in constant pool
- throw new AnnotationFormatError(e);
- }
- }
-
- private static Annotation[][] parseParameterAnnotations2(
- byte[] rawAnnotations,
- ConstantPool constPool,
- Class container) {
- ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
- int numParameters = buf.get() & 0xFF;
- Annotation[][] result = new Annotation[numParameters][];
-
- for (int i = 0; i < numParameters; i++) {
- int numAnnotations = buf.getShort() & 0xFFFF;
- List<Annotation> annotations =
- new ArrayList<Annotation>(numAnnotations);
- for (int j = 0; j < numAnnotations; j++) {
- Annotation a = parseAnnotation(buf, constPool, container, false);
- if (a != null) {
- AnnotationType type = AnnotationType.getInstance(
- a.annotationType());
- if (type.retention() == RetentionPolicy.RUNTIME)
- annotations.add(a);
- }
- }
- result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
- }
- return result;
- }
-
- private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
- new Annotation[0];
-
- /**
- * Parses the annotation at the current position in the specified
- * byte buffer, resolving constant references in the specified constant
- * pool. The cursor of the byte buffer must point to an "annotation
- * structure" as described in the RuntimeVisibleAnnotations_attribute:
- *
- * annotation {
- * u2 type_index;
- * u2 num_member_value_pairs;
- * { u2 member_name_index;
- * member_value value;
- * } member_value_pairs[num_member_value_pairs];
- * }
- * }
- *
- * Returns the annotation, or null if the annotation's type cannot
- * be found by the VM, or is not a valid annotation type.
- *
- * @param exceptionOnMissingAnnotationClass if true, throw
- * TypeNotPresentException if a referenced annotation type is not
- * available at runtime
- */
- private static Annotation parseAnnotation(ByteBuffer buf,
- ConstantPool constPool,
- Class container,
- boolean exceptionOnMissingAnnotationClass) {
- int typeIndex = buf.getShort() & 0xFFFF;
- Class annotationClass = null;
- String sig = "[unknown]";
- try {
- try {
- sig = constPool.getUTF8At(typeIndex);
- annotationClass = parseSig(sig, container);
- } catch (IllegalArgumentException ex) {
- // support obsolete early jsr175 format class files
- annotationClass = constPool.getClassAt(typeIndex);
- }
- } catch (NoClassDefFoundError e) {
- if (exceptionOnMissingAnnotationClass)
- // note: at this point sig is "[unknown]" or VM-style
- // name instead of a binary name
- throw new TypeNotPresentException(sig, e);
- skipAnnotation(buf, false);
- return null;
- }
- catch (TypeNotPresentException e) {
- if (exceptionOnMissingAnnotationClass)
- throw e;
- skipAnnotation(buf, false);
- return null;
- }
- AnnotationType type = null;
- try {
- type = AnnotationType.getInstance(annotationClass);
- } catch (IllegalArgumentException e) {
- skipAnnotation(buf, false);
- return null;
- }
-
- Map<String, Class> memberTypes = type.memberTypes();
- Map<String, Object> memberValues =
- new LinkedHashMap<String, Object>(type.memberDefaults());
-
- int numMembers = buf.getShort() & 0xFFFF;
- for (int i = 0; i < numMembers; i++) {
- int memberNameIndex = buf.getShort() & 0xFFFF;
- String memberName = constPool.getUTF8At(memberNameIndex);
- Class memberType = memberTypes.get(memberName);
-
- if (memberType == null) {
- // Member is no longer present in annotation type; ignore it
- skipMemberValue(buf);
- } else {
- Object value = parseMemberValue(memberType, buf, constPool, container);
- if (value instanceof AnnotationTypeMismatchExceptionProxy)
- ((AnnotationTypeMismatchExceptionProxy) value).
- setMember(type.members().get(memberName));
- memberValues.put(memberName, value);
- }
- }
- return annotationForMap(annotationClass, memberValues);
- }
-
- /**
- * Returns an annotation of the given type backed by the given
- * member -> value map.
- */
- public static Annotation annotationForMap(
- Class type, Map<String, Object> memberValues)
- {
- return (Annotation) Proxy.newProxyInstance(
- type.getClassLoader(), new Class[] { type },
- new AnnotationInvocationHandler(type, memberValues));
- }
-
- /**
- * Parses the annotation member value at the current position in the
- * specified byte buffer, resolving constant references in the specified
- * constant pool. The cursor of the byte buffer must point to a
- * "member_value structure" as described in the
- * RuntimeVisibleAnnotations_attribute:
- *
- * member_value {
- * u1 tag;
- * union {
- * u2 const_value_index;
- * {
- * u2 type_name_index;
- * u2 const_name_index;
- * } enum_const_value;
- * u2 class_info_index;
- * annotation annotation_value;
- * {
- * u2 num_values;
- * member_value values[num_values];
- * } array_value;
- * } value;
- * }
- *
- * The member must be of the indicated type. If it is not, this
- * method returns an AnnotationTypeMismatchExceptionProxy.
- */
- public static Object parseMemberValue(Class memberType, ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- Object result = null;
- int tag = buf.get();
- switch(tag) {
- case 'e':
- return parseEnumValue(memberType, buf, constPool, container);
- case 'c':
- result = parseClassValue(buf, constPool, container);
- break;
- case '@':
- result = parseAnnotation(buf, constPool, container, true);
- break;
- case '[':
- return parseArray(memberType, buf, constPool, container);
- default:
- result = parseConst(tag, buf, constPool);
- }
-
- if (!(result instanceof ExceptionProxy) &&
- !memberType.isInstance(result))
- result = new AnnotationTypeMismatchExceptionProxy(
- result.getClass() + "[" + result + "]");
- return result;
- }
-
- /**
- * Parses the primitive or String annotation member value indicated by
- * the specified tag byte at the current position in the specified byte
- * buffer, resolving constant reference in the specified constant pool.
- * The cursor of the byte buffer must point to an annotation member value
- * of the type indicated by the specified tag, as described in the
- * RuntimeVisibleAnnotations_attribute:
- *
- * u2 const_value_index;
- */
- private static Object parseConst(int tag,
- ByteBuffer buf, ConstantPool constPool) {
- int constIndex = buf.getShort() & 0xFFFF;
- switch(tag) {
- case 'B':
- return Byte.valueOf((byte) constPool.getIntAt(constIndex));
- case 'C':
- return Character.valueOf((char) constPool.getIntAt(constIndex));
- case 'D':
- return Double.valueOf(constPool.getDoubleAt(constIndex));
- case 'F':
- return Float.valueOf(constPool.getFloatAt(constIndex));
- case 'I':
- return Integer.valueOf(constPool.getIntAt(constIndex));
- case 'J':
- return Long.valueOf(constPool.getLongAt(constIndex));
- case 'S':
- return Short.valueOf((short) constPool.getIntAt(constIndex));
- case 'Z':
- return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
- case 's':
- return constPool.getUTF8At(constIndex);
- default:
- throw new AnnotationFormatError(
- "Invalid member-value tag in annotation: " + tag);
- }
- }
-
- /**
- * Parses the Class member value at the current position in the
- * specified byte buffer, resolving constant references in the specified
- * constant pool. The cursor of the byte buffer must point to a "class
- * info index" as described in the RuntimeVisibleAnnotations_attribute:
- *
- * u2 class_info_index;
- */
- private static Object parseClassValue(ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- int classIndex = buf.getShort() & 0xFFFF;
- try {
- try {
- String sig = constPool.getUTF8At(classIndex);
- return parseSig(sig, container);
- } catch (IllegalArgumentException ex) {
- // support obsolete early jsr175 format class files
- return constPool.getClassAt(classIndex);
- }
- } catch (NoClassDefFoundError e) {
- return new TypeNotPresentExceptionProxy("[unknown]", e);
- }
- catch (TypeNotPresentException e) {
- return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
- }
- }
-
- /**
- * Parses a return type signature and returns the according Class object.
- */
- private static Class<?> parseSig(String sig, Class container) {
- if (sig.equals("V")) {
- return void.class;
- }
- else {
- return toClass(new FieldSignatureParser(container, sig).getFieldType());
- }
- }
-
- static Class<?> toClass(Type o) {
- if (o instanceof GenericArrayType)
- return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
- 0)
- .getClass();
- return (Class<?>)o;
- }
-
- /**
- * Parses the enum constant member value at the current position in the
- * specified byte buffer, resolving constant references in the specified
- * constant pool. The cursor of the byte buffer must point to a
- * "enum_const_value structure" as described in the
- * RuntimeVisibleAnnotations_attribute:
- *
- * {
- * u2 type_name_index;
- * u2 const_name_index;
- * } enum_const_value;
- */
- private static Object parseEnumValue(Class enumType, ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- int typeNameIndex = buf.getShort() & 0xFFFF;
- String typeName = constPool.getUTF8At(typeNameIndex);
- int constNameIndex = buf.getShort() & 0xFFFF;
- String constName = constPool.getUTF8At(constNameIndex);
-
- if (!typeName.endsWith(";")) {
- // support now-obsolete early jsr175-format class files.
- if (!enumType.getName().equals(typeName))
- return new AnnotationTypeMismatchExceptionProxy(
- typeName + "." + constName);
- } else if (enumType != parseSig(typeName, container)) {
- return new AnnotationTypeMismatchExceptionProxy(
- typeName + "." + constName);
- }
-
- try {
- return Enum.valueOf(enumType, constName);
- } catch(IllegalArgumentException e) {
- return new EnumConstantNotPresentExceptionProxy(
- (Class<? extends Enum>)enumType, constName);
- }
- }
-
- /**
- * Parses the array value at the current position in the specified byte
- * buffer, resolving constant references in the specified constant pool.
- * The cursor of the byte buffer must point to an array value struct
- * as specified in the RuntimeVisibleAnnotations_attribute:
- *
- * {
- * u2 num_values;
- * member_value values[num_values];
- * } array_value;
- *
- * If the array values do not match arrayType, an
- * AnnotationTypeMismatchExceptionProxy will be returned.
- */
- private static Object parseArray(Class arrayType,
- ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- int length = buf.getShort() & 0xFFFF; // Number of array components
- Class componentType = arrayType.getComponentType();
-
- if (componentType == byte.class) {
- return parseByteArray(length, buf, constPool);
- } else if (componentType == char.class) {
- return parseCharArray(length, buf, constPool);
- } else if (componentType == double.class) {
- return parseDoubleArray(length, buf, constPool);
- } else if (componentType == float.class) {
- return parseFloatArray(length, buf, constPool);
- } else if (componentType == int.class) {
- return parseIntArray(length, buf, constPool);
- } else if (componentType == long.class) {
- return parseLongArray(length, buf, constPool);
- } else if (componentType == short.class) {
- return parseShortArray(length, buf, constPool);
- } else if (componentType == boolean.class) {
- return parseBooleanArray(length, buf, constPool);
- } else if (componentType == String.class) {
- return parseStringArray(length, buf, constPool);
- } else if (componentType == Class.class) {
- return parseClassArray(length, buf, constPool, container);
- } else if (componentType.isEnum()) {
- return parseEnumArray(length, componentType, buf,
- constPool, container);
- } else {
- assert componentType.isAnnotation();
- return parseAnnotationArray(length, componentType, buf,
- constPool, container);
- }
- }
-
- private static Object parseByteArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- byte[] result = new byte[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'B') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = (byte) constPool.getIntAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseCharArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- char[] result = new char[length];
- boolean typeMismatch = false;
- byte tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'C') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = (char) constPool.getIntAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseDoubleArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- double[] result = new double[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'D') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = constPool.getDoubleAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseFloatArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- float[] result = new float[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'F') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = constPool.getFloatAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseIntArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- int[] result = new int[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'I') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = constPool.getIntAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseLongArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- long[] result = new long[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'J') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = constPool.getLongAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseShortArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- short[] result = new short[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'S') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = (short) constPool.getIntAt(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseBooleanArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- boolean[] result = new boolean[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'Z') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = (constPool.getIntAt(index) != 0);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseStringArray(int length,
- ByteBuffer buf, ConstantPool constPool) {
- String[] result = new String[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 's') {
- int index = buf.getShort() & 0xFFFF;
- result[i] = constPool.getUTF8At(index);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseClassArray(int length,
- ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- Object[] result = new Class[length];
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'c') {
- result[i] = parseClassValue(buf, constPool, container);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseEnumArray(int length, Class enumType,
- ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- Object[] result = (Object[]) Array.newInstance(enumType, length);
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == 'e') {
- result[i] = parseEnumValue(enumType, buf, constPool, container);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- private static Object parseAnnotationArray(int length,
- Class annotationType,
- ByteBuffer buf,
- ConstantPool constPool,
- Class container) {
- Object[] result = (Object[]) Array.newInstance(annotationType, length);
- boolean typeMismatch = false;
- int tag = 0;
-
- for (int i = 0; i < length; i++) {
- tag = buf.get();
- if (tag == '@') {
- result[i] = parseAnnotation(buf, constPool, container, true);
- } else {
- skipMemberValue(tag, buf);
- typeMismatch = true;
- }
- }
- return typeMismatch ? exceptionProxy(tag) : result;
- }
-
- /**
- * Return an appropriate exception proxy for a mismatching array
- * annotation where the erroneous array has the specified tag.
- */
- private static ExceptionProxy exceptionProxy(int tag) {
- return new AnnotationTypeMismatchExceptionProxy(
- "Array with component tag: " + tag);
- }
-
- /**
- * Skips the annotation at the current position in the specified
- * byte buffer. The cursor of the byte buffer must point to
- * an "annotation structure" OR two bytes into an annotation
- * structure (i.e., after the type index).
- *
- * @parameter complete true if the byte buffer points to the beginning
- * of an annotation structure (rather than two bytes in).
- */
- private static void skipAnnotation(ByteBuffer buf, boolean complete) {
- if (complete)
- buf.getShort(); // Skip type index
- int numMembers = buf.getShort() & 0xFFFF;
- for (int i = 0; i < numMembers; i++) {
- buf.getShort(); // Skip memberNameIndex
- skipMemberValue(buf);
- }
- }
-
- /**
- * Skips the annotation member value at the current position in the
- * specified byte buffer. The cursor of the byte buffer must point to a
- * "member_value structure."
- */
- private static void skipMemberValue(ByteBuffer buf) {
- int tag = buf.get();
- skipMemberValue(tag, buf);
- }
-
- /**
- * Skips the annotation member value at the current position in the
- * specified byte buffer. The cursor of the byte buffer must point
- * immediately after the tag in a "member_value structure."
- */
- private static void skipMemberValue(int tag, ByteBuffer buf) {
- switch(tag) {
- case 'e': // Enum value
- buf.getInt(); // (Two shorts, actually.)
- break;
- case '@':
- skipAnnotation(buf, true);
- break;
- case '[':
- skipArray(buf);
- break;
- default:
- // Class, primitive, or String
- buf.getShort();
- }
- }
-
- /**
- * Skips the array value at the current position in the specified byte
- * buffer. The cursor of the byte buffer must point to an array value
- * struct.
- */
- private static void skipArray(ByteBuffer buf) {
- int length = buf.getShort() & 0xFFFF;
- for (int i = 0; i < length; i++)
- skipMemberValue(buf);
- }
-}