sun.reflect.annotation.AnnotationParser Maven / Gradle / Ivy
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.reflect.annotation;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.function.Supplier;
import java.security.AccessController;
import java.security.PrivilegedAction;
//import jdk.internal.reflect.ConstantPool;
//import sun.reflect.generics.parser.SignatureParser;
//import sun.reflect.generics.tree.TypeSignature;
//import sun.reflect.generics.factory.GenericsFactory;
//import sun.reflect.generics.factory.CoreReflectionFactory;
//import sun.reflect.generics.visitor.Reifier;
//import sun.reflect.generics.scope.ClassScope;
/**
* 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 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, Annotation> parseAnnotations(
// byte[] rawAnnotations,
// ConstantPool constPool,
// Class> container) {
// if (rawAnnotations == null)
// return Collections.emptyMap();
//
// try {
// return parseAnnotations2(rawAnnotations, constPool, container, null);
// } catch(BufferUnderflowException e) {
// throw new AnnotationFormatError("Unexpected end of annotations.");
// } catch(IllegalArgumentException e) {
// // Type mismatch in constant pool
// throw new AnnotationFormatError(e);
// }
// }
//
// /**
// * Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
// * with an additional parameter {@code selectAnnotationClasses} which selects the
// * annotation types to parse (other than selected are quickly skipped).
// * This method is only used to parse select meta annotations in the construction
// * phase of {@link AnnotationType} instances to prevent infinite recursion.
// *
// * @param selectAnnotationClasses an array of annotation types to select when parsing
// */
// @SafeVarargs
// @SuppressWarnings("varargs") // selectAnnotationClasses is used safely
// static Map, Annotation> parseSelectAnnotations(
// byte[] rawAnnotations,
// ConstantPool constPool,
// Class> container,
// Class extends Annotation> ... selectAnnotationClasses) {
// if (rawAnnotations == null)
// return Collections.emptyMap();
//
// try {
// return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
// } 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, Annotation> parseAnnotations2(
// byte[] rawAnnotations,
// ConstantPool constPool,
// Class> container,
// Class extends Annotation>[] selectAnnotationClasses) {
// Map, Annotation> result =
// new LinkedHashMap, Annotation>();
// ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
// int numAnnotations = buf.getShort() & 0xFFFF;
// for (int i = 0; i < numAnnotations; i++) {
// Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
// if (a != null) {
// Class extends Annotation> klass = a.annotationType();
// if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
// 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 annotations =
// new ArrayList(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
// */
// static Annotation parseAnnotation(ByteBuffer buf,
// ConstantPool constPool,
// Class> container,
// boolean exceptionOnMissingAnnotationClass) {
// return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
// }
//
// @SuppressWarnings("unchecked")
// private static Annotation parseAnnotation2(ByteBuffer buf,
// ConstantPool constPool,
// Class> container,
// boolean exceptionOnMissingAnnotationClass,
// Class extends Annotation>[] selectAnnotationClasses) {
// int typeIndex = buf.getShort() & 0xFFFF;
// Class extends Annotation> annotationClass = null;
// String sig = "[unknown]";
// try {
// try {
// sig = constPool.getUTF8At(typeIndex);
// annotationClass = (Class extends Annotation>)parseSig(sig, container);
// } catch (IllegalArgumentException ex) {
// // support obsolete early jsr175 format class files
// annotationClass = (Class extends Annotation>)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;
// }
// if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
// skipAnnotation(buf, false);
// return null;
// }
// AnnotationType type = null;
// try {
// type = AnnotationType.getInstance(annotationClass);
// } catch (IllegalArgumentException e) {
// skipAnnotation(buf, false);
// return null;
// }
//
// Map> memberTypes = type.memberTypes();
// Map memberValues =
// new LinkedHashMap(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 {@literal ->} value map.
*/
public static Annotation annotationForMap(final Class extends Annotation> type,
final Map memberValues)
{
return AccessController.doPrivileged(new PrivilegedAction() {
public Annotation run() {
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.
// */
// @SuppressWarnings("unchecked")
// 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((Class extends Enum>>)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());
// }
// }
//
// private static Class> parseSig(String sig, Class> container) {
// if (sig.equals("V")) return void.class;
// SignatureParser parser = SignatureParser.make();
// TypeSignature typeSig = parser.parseTypeSig(sig);
// GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
// Reifier reify = Reifier.make(factory);
// typeSig.accept(reify);
// Type result = reify.getResult();
// return toClass(result);
// }
// 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;
// */
// @SuppressWarnings({"rawtypes", "unchecked"})
// private static Object parseEnumValue(Class extends Enum> 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.
// */
// @SuppressWarnings("unchecked")
// 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, (Class extends Enum>>)componentType, buf,
// constPool, container);
// } else {
// assert componentType.isAnnotation();
// return parseAnnotationArray(length, (Class extends Annotation>)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) {
// return parseArrayElements(new Class>[length],
// buf, 'c', () -> parseClassValue(buf, constPool, container));
// }
//
// private static Object parseEnumArray(int length, Class extends Enum>> enumType,
// ByteBuffer buf,
// ConstantPool constPool,
// Class> container) {
// return parseArrayElements((Object[]) Array.newInstance(enumType, length),
// buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container));
// }
//
// private static Object parseAnnotationArray(int length,
// Class extends Annotation> annotationType,
// ByteBuffer buf,
// ConstantPool constPool,
// Class> container) {
// return parseArrayElements((Object[]) Array.newInstance(annotationType, length),
// buf, '@', () -> parseAnnotation(buf, constPool, container, true));
// }
//
// private static Object parseArrayElements(Object[] result,
// ByteBuffer buf,
// int expectedTag,
// Supplier