Path: blob/master/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java
67770 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.reflect.annotation;2627import java.lang.annotation.*;28import java.lang.reflect.*;29import java.nio.BufferUnderflowException;30import java.nio.ByteBuffer;31import java.util.*;32import java.util.function.Supplier;33import java.security.AccessController;34import java.security.PrivilegedAction;35import jdk.internal.reflect.ConstantPool;3637import sun.reflect.generics.parser.SignatureParser;38import sun.reflect.generics.tree.TypeSignature;39import sun.reflect.generics.factory.GenericsFactory;40import sun.reflect.generics.factory.CoreReflectionFactory;41import sun.reflect.generics.visitor.Reifier;42import sun.reflect.generics.scope.ClassScope;4344/**45* Parser for Java programming language annotations. Translates46* annotation byte streams emitted by compiler into annotation objects.47*48* @author Josh Bloch49* @since 1.550*/51public class AnnotationParser {52/**53* Parses the annotations described by the specified byte array.54* resolving constant references in the specified constant pool.55* The array must contain an array of annotations as described56* in the RuntimeVisibleAnnotations_attribute:57*58* u2 num_annotations;59* annotation annotations[num_annotations];60*61* @throws AnnotationFormatError if an annotation is found to be62* malformed.63*/64public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(65byte[] rawAnnotations,66ConstantPool constPool,67Class<?> container) {68if (rawAnnotations == null)69return Collections.emptyMap();7071try {72return parseAnnotations2(rawAnnotations, constPool, container, null);73} catch(BufferUnderflowException e) {74throw new AnnotationFormatError("Unexpected end of annotations.");75} catch(IllegalArgumentException e) {76// Type mismatch in constant pool77throw new AnnotationFormatError(e);78}79}8081/**82* Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}83* with an additional parameter {@code selectAnnotationClasses} which selects the84* annotation types to parse (other than selected are quickly skipped).<p>85* This method is only used to parse select meta annotations in the construction86* phase of {@link AnnotationType} instances to prevent infinite recursion.87*88* @param selectAnnotationClasses an array of annotation types to select when parsing89*/90@SafeVarargs91@SuppressWarnings("varargs") // selectAnnotationClasses is used safely92static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(93byte[] rawAnnotations,94ConstantPool constPool,95Class<?> container,96Class<? extends Annotation> ... selectAnnotationClasses) {97if (rawAnnotations == null)98return Collections.emptyMap();99100try {101return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);102} catch(BufferUnderflowException e) {103throw new AnnotationFormatError("Unexpected end of annotations.");104} catch(IllegalArgumentException e) {105// Type mismatch in constant pool106throw new AnnotationFormatError(e);107}108}109110private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(111byte[] rawAnnotations,112ConstantPool constPool,113Class<?> container,114Class<? extends Annotation>[] selectAnnotationClasses) {115Map<Class<? extends Annotation>, Annotation> result =116new LinkedHashMap<Class<? extends Annotation>, Annotation>();117ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);118int numAnnotations = buf.getShort() & 0xFFFF;119for (int i = 0; i < numAnnotations; i++) {120Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);121if (a != null) {122Class<? extends Annotation> klass = a.annotationType();123if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&124result.put(klass, a) != null) {125throw new AnnotationFormatError(126"Duplicate annotation for class: "+klass+": " + a);127}128}129}130return result;131}132133/**134* Parses the parameter annotations described by the specified byte array.135* resolving constant references in the specified constant pool.136* The array must contain an array of annotations as described137* in the RuntimeVisibleParameterAnnotations_attribute:138*139* u1 num_parameters;140* {141* u2 num_annotations;142* annotation annotations[num_annotations];143* } parameter_annotations[num_parameters];144*145* Unlike parseAnnotations, rawAnnotations must not be null!146* A null value must be handled by the caller. This is so because147* we cannot determine the number of parameters if rawAnnotations148* is null. Also, the caller should check that the number149* of parameters indicated by the return value of this method150* matches the actual number of method parameters. A mismatch151* indicates that an AnnotationFormatError should be thrown.152*153* @throws AnnotationFormatError if an annotation is found to be154* malformed.155*/156public static Annotation[][] parseParameterAnnotations(157byte[] rawAnnotations,158ConstantPool constPool,159Class<?> container) {160try {161return parseParameterAnnotations2(rawAnnotations, constPool, container);162} catch(BufferUnderflowException e) {163throw new AnnotationFormatError(164"Unexpected end of parameter annotations.");165} catch(IllegalArgumentException e) {166// Type mismatch in constant pool167throw new AnnotationFormatError(e);168}169}170171private static Annotation[][] parseParameterAnnotations2(172byte[] rawAnnotations,173ConstantPool constPool,174Class<?> container) {175ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);176int numParameters = buf.get() & 0xFF;177Annotation[][] result = new Annotation[numParameters][];178179for (int i = 0; i < numParameters; i++) {180int numAnnotations = buf.getShort() & 0xFFFF;181List<Annotation> annotations =182new ArrayList<Annotation>(numAnnotations);183for (int j = 0; j < numAnnotations; j++) {184Annotation a = parseAnnotation(buf, constPool, container, false);185if (a != null) {186AnnotationType type = AnnotationType.getInstance(187a.annotationType());188if (type.retention() == RetentionPolicy.RUNTIME)189annotations.add(a);190}191}192result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);193}194return result;195}196197private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =198new Annotation[0];199200/**201* Parses the annotation at the current position in the specified202* byte buffer, resolving constant references in the specified constant203* pool. The cursor of the byte buffer must point to an "annotation204* structure" as described in the RuntimeVisibleAnnotations_attribute:205*206* annotation {207* u2 type_index;208* u2 num_member_value_pairs;209* { u2 member_name_index;210* member_value value;211* } member_value_pairs[num_member_value_pairs];212* }213* }214*215* Returns the annotation, or null if the annotation's type cannot216* be found by the VM, or is not a valid annotation type.217*218* @param exceptionOnMissingAnnotationClass if true, throw219* TypeNotPresentException if a referenced annotation type is not220* available at runtime221*/222static Annotation parseAnnotation(ByteBuffer buf,223ConstantPool constPool,224Class<?> container,225boolean exceptionOnMissingAnnotationClass) {226return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);227}228229@SuppressWarnings("unchecked")230private static Annotation parseAnnotation2(ByteBuffer buf,231ConstantPool constPool,232Class<?> container,233boolean exceptionOnMissingAnnotationClass,234Class<? extends Annotation>[] selectAnnotationClasses) {235int typeIndex = buf.getShort() & 0xFFFF;236Class<? extends Annotation> annotationClass = null;237String sig = "[unknown]";238try {239sig = constPool.getUTF8At(typeIndex);240annotationClass = (Class<? extends Annotation>)parseSig(sig, container);241} catch (NoClassDefFoundError e) {242if (exceptionOnMissingAnnotationClass)243// note: at this point sig is "[unknown]" or VM-style244// name instead of a binary name245throw new TypeNotPresentException(sig, e);246skipAnnotation(buf, false);247return null;248}249catch (TypeNotPresentException e) {250if (exceptionOnMissingAnnotationClass)251throw e;252skipAnnotation(buf, false);253return null;254}255if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {256skipAnnotation(buf, false);257return null;258}259AnnotationType type = null;260try {261type = AnnotationType.getInstance(annotationClass);262} catch (IllegalArgumentException e) {263skipAnnotation(buf, false);264return null;265}266267Map<String, Class<?>> memberTypes = type.memberTypes();268Map<String, Object> memberValues =269new LinkedHashMap<String, Object>(type.memberDefaults());270271int numMembers = buf.getShort() & 0xFFFF;272for (int i = 0; i < numMembers; i++) {273int memberNameIndex = buf.getShort() & 0xFFFF;274String memberName = constPool.getUTF8At(memberNameIndex);275Class<?> memberType = memberTypes.get(memberName);276277if (memberType == null) {278// Member is no longer present in annotation type; ignore it279skipMemberValue(buf);280} else {281Object value = parseMemberValue(memberType, buf, constPool, container);282if (value instanceof AnnotationTypeMismatchExceptionProxy)283((AnnotationTypeMismatchExceptionProxy) value).284setMember(type.members().get(memberName));285memberValues.put(memberName, value);286}287}288return annotationForMap(annotationClass, memberValues);289}290291/**292* Returns an annotation of the given type backed by the given293* member {@literal ->} value map.294*/295@SuppressWarnings("removal")296public static Annotation annotationForMap(final Class<? extends Annotation> type,297final Map<String, Object> memberValues)298{299return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {300public Annotation run() {301return (Annotation) Proxy.newProxyInstance(302type.getClassLoader(), new Class<?>[] { type },303new AnnotationInvocationHandler(type, memberValues));304}});305}306307/**308* Parses the annotation member value at the current position in the309* specified byte buffer, resolving constant references in the specified310* constant pool. The cursor of the byte buffer must point to a311* "member_value structure" as described in the312* RuntimeVisibleAnnotations_attribute:313*314* member_value {315* u1 tag;316* union {317* u2 const_value_index;318* {319* u2 type_name_index;320* u2 const_name_index;321* } enum_const_value;322* u2 class_info_index;323* annotation annotation_value;324* {325* u2 num_values;326* member_value values[num_values];327* } array_value;328* } value;329* }330*331* The member must be of the indicated type. If it is not, this332* method returns an AnnotationTypeMismatchExceptionProxy.333*/334@SuppressWarnings("unchecked")335public static Object parseMemberValue(Class<?> memberType,336ByteBuffer buf,337ConstantPool constPool,338Class<?> container) {339Object result = null;340int tag = buf.get();341switch(tag) {342case 'e':343return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);344case 'c':345result = parseClassValue(buf, constPool, container);346break;347case '@':348result = parseAnnotation(buf, constPool, container, true);349break;350case '[':351return parseArray(memberType, buf, constPool, container);352default:353result = parseConst(tag, buf, constPool);354}355356if (result == null) {357result = new AnnotationTypeMismatchExceptionProxy(358Proxy.isProxyClass(memberType)359? memberType.getInterfaces()[0].getName()360: memberType.getName());361} else if (!(result instanceof ExceptionProxy) &&362!memberType.isInstance(result)) {363if (result instanceof Annotation) {364result = new AnnotationTypeMismatchExceptionProxy(365result.toString());366} else {367result = new AnnotationTypeMismatchExceptionProxy(368result.getClass().getName() + "[" + result + "]");369}370}371return result;372}373374/**375* Parses the primitive or String annotation member value indicated by376* the specified tag byte at the current position in the specified byte377* buffer, resolving constant reference in the specified constant pool.378* The cursor of the byte buffer must point to an annotation member value379* of the type indicated by the specified tag, as described in the380* RuntimeVisibleAnnotations_attribute:381*382* u2 const_value_index;383*/384private static Object parseConst(int tag,385ByteBuffer buf, ConstantPool constPool) {386int constIndex = buf.getShort() & 0xFFFF;387switch(tag) {388case 'B':389return Byte.valueOf((byte) constPool.getIntAt(constIndex));390case 'C':391return Character.valueOf((char) constPool.getIntAt(constIndex));392case 'D':393return Double.valueOf(constPool.getDoubleAt(constIndex));394case 'F':395return Float.valueOf(constPool.getFloatAt(constIndex));396case 'I':397return Integer.valueOf(constPool.getIntAt(constIndex));398case 'J':399return Long.valueOf(constPool.getLongAt(constIndex));400case 'S':401return Short.valueOf((short) constPool.getIntAt(constIndex));402case 'Z':403return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);404case 's':405return constPool.getUTF8At(constIndex);406default:407throw new AnnotationFormatError(408"Invalid member-value tag in annotation: " + tag);409}410}411412/**413* Parses the Class member value at the current position in the414* specified byte buffer, resolving constant references in the specified415* constant pool. The cursor of the byte buffer must point to a "class416* info index" as described in the RuntimeVisibleAnnotations_attribute:417*418* u2 class_info_index;419*/420private static Object parseClassValue(ByteBuffer buf,421ConstantPool constPool,422Class<?> container) {423int classIndex = buf.getShort() & 0xFFFF;424try {425String sig = constPool.getUTF8At(classIndex);426return parseSig(sig, container);427} catch (NoClassDefFoundError e) {428return new TypeNotPresentExceptionProxy("[unknown]", e);429} catch (TypeNotPresentException e) {430return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());431}432}433434private static Class<?> parseSig(String sig, Class<?> container) {435if (sig.equals("V")) return void.class;436SignatureParser parser = SignatureParser.make();437TypeSignature typeSig = parser.parseTypeSig(sig);438GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));439Reifier reify = Reifier.make(factory);440typeSig.accept(reify);441Type result = reify.getResult();442return toClass(result);443}444static Class<?> toClass(Type o) {445if (o instanceof GenericArrayType)446return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),4470)448.getClass();449return (Class)o;450}451452/**453* Parses the enum constant member value at the current position in the454* specified byte buffer, resolving constant references in the specified455* constant pool. The cursor of the byte buffer must point to a456* "enum_const_value structure" as described in the457* RuntimeVisibleAnnotations_attribute:458*459* {460* u2 type_name_index;461* u2 const_name_index;462* } enum_const_value;463*/464@SuppressWarnings({"rawtypes", "unchecked"})465private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,466ConstantPool constPool,467Class<?> container) {468int typeNameIndex = buf.getShort() & 0xFFFF;469String typeName = constPool.getUTF8At(typeNameIndex);470int constNameIndex = buf.getShort() & 0xFFFF;471String constName = constPool.getUTF8At(constNameIndex);472if (!enumType.isEnum() || enumType != parseSig(typeName, container)) {473return new AnnotationTypeMismatchExceptionProxy(474typeName.substring(1, typeName.length() - 1).replace('/', '.') + "." + constName);475}476477try {478return Enum.valueOf(enumType, constName);479} catch(IllegalArgumentException e) {480return new EnumConstantNotPresentExceptionProxy(481(Class<? extends Enum<?>>)enumType, constName);482}483}484485/**486* Parses the array value at the current position in the specified byte487* buffer, resolving constant references in the specified constant pool.488* The cursor of the byte buffer must point to an array value struct489* as specified in the RuntimeVisibleAnnotations_attribute:490*491* {492* u2 num_values;493* member_value values[num_values];494* } array_value;495*496* If the array values do not match arrayType, an497* AnnotationTypeMismatchExceptionProxy will be returned.498*/499@SuppressWarnings("unchecked")500private static Object parseArray(Class<?> arrayType,501ByteBuffer buf,502ConstantPool constPool,503Class<?> container) {504int length = buf.getShort() & 0xFFFF; // Number of array components505Class<?> componentType = arrayType.getComponentType();506507if (componentType == byte.class) {508return parseByteArray(length, buf, constPool);509} else if (componentType == char.class) {510return parseCharArray(length, buf, constPool);511} else if (componentType == double.class) {512return parseDoubleArray(length, buf, constPool);513} else if (componentType == float.class) {514return parseFloatArray(length, buf, constPool);515} else if (componentType == int.class) {516return parseIntArray(length, buf, constPool);517} else if (componentType == long.class) {518return parseLongArray(length, buf, constPool);519} else if (componentType == short.class) {520return parseShortArray(length, buf, constPool);521} else if (componentType == boolean.class) {522return parseBooleanArray(length, buf, constPool);523} else if (componentType == String.class) {524return parseStringArray(length, buf, constPool);525} else if (componentType == Class.class) {526return parseClassArray(length, buf, constPool, container);527} else if (componentType.isEnum()) {528return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf,529constPool, container);530} else if (componentType.isAnnotation()) {531return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,532constPool, container);533} else {534return parseUnknownArray(length, buf);535}536}537538private static Object parseByteArray(int length,539ByteBuffer buf, ConstantPool constPool) {540byte[] result = new byte[length];541boolean typeMismatch = false;542int tag = 0;543544for (int i = 0; i < length; i++) {545tag = buf.get();546if (tag == 'B') {547int index = buf.getShort() & 0xFFFF;548result[i] = (byte) constPool.getIntAt(index);549} else {550skipMemberValue(tag, buf);551typeMismatch = true;552}553}554return typeMismatch ? exceptionProxy(tag) : result;555}556557private static Object parseCharArray(int length,558ByteBuffer buf, ConstantPool constPool) {559char[] result = new char[length];560boolean typeMismatch = false;561byte tag = 0;562563for (int i = 0; i < length; i++) {564tag = buf.get();565if (tag == 'C') {566int index = buf.getShort() & 0xFFFF;567result[i] = (char) constPool.getIntAt(index);568} else {569skipMemberValue(tag, buf);570typeMismatch = true;571}572}573return typeMismatch ? exceptionProxy(tag) : result;574}575576private static Object parseDoubleArray(int length,577ByteBuffer buf, ConstantPool constPool) {578double[] result = new double[length];579boolean typeMismatch = false;580int tag = 0;581582for (int i = 0; i < length; i++) {583tag = buf.get();584if (tag == 'D') {585int index = buf.getShort() & 0xFFFF;586result[i] = constPool.getDoubleAt(index);587} else {588skipMemberValue(tag, buf);589typeMismatch = true;590}591}592return typeMismatch ? exceptionProxy(tag) : result;593}594595private static Object parseFloatArray(int length,596ByteBuffer buf, ConstantPool constPool) {597float[] result = new float[length];598boolean typeMismatch = false;599int tag = 0;600601for (int i = 0; i < length; i++) {602tag = buf.get();603if (tag == 'F') {604int index = buf.getShort() & 0xFFFF;605result[i] = constPool.getFloatAt(index);606} else {607skipMemberValue(tag, buf);608typeMismatch = true;609}610}611return typeMismatch ? exceptionProxy(tag) : result;612}613614private static Object parseIntArray(int length,615ByteBuffer buf, ConstantPool constPool) {616int[] result = new int[length];617boolean typeMismatch = false;618int tag = 0;619620for (int i = 0; i < length; i++) {621tag = buf.get();622if (tag == 'I') {623int index = buf.getShort() & 0xFFFF;624result[i] = constPool.getIntAt(index);625} else {626skipMemberValue(tag, buf);627typeMismatch = true;628}629}630return typeMismatch ? exceptionProxy(tag) : result;631}632633private static Object parseLongArray(int length,634ByteBuffer buf, ConstantPool constPool) {635long[] result = new long[length];636boolean typeMismatch = false;637int tag = 0;638639for (int i = 0; i < length; i++) {640tag = buf.get();641if (tag == 'J') {642int index = buf.getShort() & 0xFFFF;643result[i] = constPool.getLongAt(index);644} else {645skipMemberValue(tag, buf);646typeMismatch = true;647}648}649return typeMismatch ? exceptionProxy(tag) : result;650}651652private static Object parseShortArray(int length,653ByteBuffer buf, ConstantPool constPool) {654short[] result = new short[length];655boolean typeMismatch = false;656int tag = 0;657658for (int i = 0; i < length; i++) {659tag = buf.get();660if (tag == 'S') {661int index = buf.getShort() & 0xFFFF;662result[i] = (short) constPool.getIntAt(index);663} else {664skipMemberValue(tag, buf);665typeMismatch = true;666}667}668return typeMismatch ? exceptionProxy(tag) : result;669}670671private static Object parseBooleanArray(int length,672ByteBuffer buf, ConstantPool constPool) {673boolean[] result = new boolean[length];674boolean typeMismatch = false;675int tag = 0;676677for (int i = 0; i < length; i++) {678tag = buf.get();679if (tag == 'Z') {680int index = buf.getShort() & 0xFFFF;681result[i] = (constPool.getIntAt(index) != 0);682} else {683skipMemberValue(tag, buf);684typeMismatch = true;685}686}687return typeMismatch ? exceptionProxy(tag) : result;688}689690private static Object parseStringArray(int length,691ByteBuffer buf, ConstantPool constPool) {692String[] result = new String[length];693boolean typeMismatch = false;694int tag = 0;695696for (int i = 0; i < length; i++) {697tag = buf.get();698if (tag == 's') {699int index = buf.getShort() & 0xFFFF;700result[i] = constPool.getUTF8At(index);701} else {702skipMemberValue(tag, buf);703typeMismatch = true;704}705}706return typeMismatch ? exceptionProxy(tag) : result;707}708709private static Object parseClassArray(int length,710ByteBuffer buf,711ConstantPool constPool,712Class<?> container) {713return parseArrayElements(new Class<?>[length],714buf, 'c', () -> parseClassValue(buf, constPool, container));715}716717private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType,718ByteBuffer buf,719ConstantPool constPool,720Class<?> container) {721return parseArrayElements((Object[]) Array.newInstance(enumType, length),722buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container));723}724725private static Object parseAnnotationArray(int length,726Class<? extends Annotation> annotationType,727ByteBuffer buf,728ConstantPool constPool,729Class<?> container) {730return parseArrayElements((Object[]) Array.newInstance(annotationType, length),731buf, '@', () -> parseAnnotation(buf, constPool, container, true));732}733734private static Object parseArrayElements(Object[] result,735ByteBuffer buf,736int expectedTag,737Supplier<Object> parseElement) {738Object exceptionProxy = null;739for (int i = 0; i < result.length; i++) {740int tag = buf.get();741if (tag == expectedTag) {742Object value = parseElement.get();743if (value instanceof ExceptionProxy) {744if (exceptionProxy == null) exceptionProxy = (ExceptionProxy) value;745} else {746result[i] = value;747}748} else {749skipMemberValue(tag, buf);750if (exceptionProxy == null) exceptionProxy = exceptionProxy(tag);751}752}753return (exceptionProxy != null) ? exceptionProxy : result;754}755756private static Object parseUnknownArray(int length,757ByteBuffer buf) {758int tag = 0;759760for (int i = 0; i < length; i++) {761tag = buf.get();762skipMemberValue(tag, buf);763}764765return exceptionProxy(tag);766}767768/**769* Returns an appropriate exception proxy for a mismatching array770* annotation where the erroneous array has the specified tag.771*/772private static ExceptionProxy exceptionProxy(int tag) {773return new AnnotationTypeMismatchExceptionProxy(774"Array with component tag: " + (tag == 0 ? "0" : (char) tag));775}776777/**778* Skips the annotation at the current position in the specified779* byte buffer. The cursor of the byte buffer must point to780* an "annotation structure" OR two bytes into an annotation781* structure (i.e., after the type index).782*783* @param complete true if the byte buffer points to the beginning784* of an annotation structure (rather than two bytes in).785*/786private static void skipAnnotation(ByteBuffer buf, boolean complete) {787if (complete)788buf.getShort(); // Skip type index789int numMembers = buf.getShort() & 0xFFFF;790for (int i = 0; i < numMembers; i++) {791buf.getShort(); // Skip memberNameIndex792skipMemberValue(buf);793}794}795796/**797* Skips the annotation member value at the current position in the798* specified byte buffer. The cursor of the byte buffer must point to a799* "member_value structure."800*/801private static void skipMemberValue(ByteBuffer buf) {802int tag = buf.get();803skipMemberValue(tag, buf);804}805806/**807* Skips the annotation member value at the current position in the808* specified byte buffer. The cursor of the byte buffer must point809* immediately after the tag in a "member_value structure."810*/811private static void skipMemberValue(int tag, ByteBuffer buf) {812switch(tag) {813case 'e': // Enum value814buf.getInt(); // (Two shorts, actually.)815break;816case '@':817skipAnnotation(buf, true);818break;819case '[':820skipArray(buf);821break;822default:823// Class, primitive, or String824buf.getShort();825}826}827828/**829* Skips the array value at the current position in the specified byte830* buffer. The cursor of the byte buffer must point to an array value831* struct.832*/833private static void skipArray(ByteBuffer buf) {834int length = buf.getShort() & 0xFFFF;835for (int i = 0; i < length; i++)836skipMemberValue(buf);837}838839/**840* Searches for given {@code element} in given {@code array} by identity.841* Returns {@code true} if found {@code false} if not.842*/843private static boolean contains(Object[] array, Object element) {844for (Object e : array)845if (e == element)846return true;847return false;848}849850/*851* This method converts the annotation map returned by the parseAnnotations()852* method to an array. It is called by Field.getDeclaredAnnotations(),853* Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().854* This avoids the reflection classes to load the Annotation class until855* it is needed.856*/857private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];858public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {859return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);860}861862static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }863}864865866