package org.hotswap.agent.javassist.bytecode; import java.io.DataInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.hotswap.agent.javassist.bytecode.annotation.TypeAnnotationsWriter; /** * A class representing * {@code RuntimeVisibleTypeAnnotations} attribute and * {@code RuntimeInvisibleTypeAnnotations} attribute. * * @since 3.19 */ public class TypeAnnotationsAttribute extends AttributeInfo { /** * The name of the {@code RuntimeVisibleTypeAnnotations} attribute. */ public static final String visibleTag = "RuntimeVisibleTypeAnnotations"; /** * The name of the {@code RuntimeInvisibleTypeAnnotations} attribute. */ public static final String invisibleTag = "RuntimeInvisibleTypeAnnotations"; /** * Constructs a <code>Runtime(In)VisibleTypeAnnotations_attribute</code>. * * @param cp constant pool * @param attrname attribute name (<code>visibleTag</code> or * <code>invisibleTag</code>). * @param info the contents of this attribute. It does not * include <code>attribute_name_index</code> or * <code>attribute_length</code>. */ public TypeAnnotationsAttribute(ConstPool cp, String attrname, byte[] info) { super(cp, attrname, info); } /** * @param n the attribute name. */ TypeAnnotationsAttribute(ConstPool cp, int n, DataInputStream in) throws IOException { super(cp, n, in); } /** * Returns <code>num_annotations</code>. */ public int numAnnotations() { return ByteArray.readU16bit(info, 0); } /** * Copies this attribute and returns a new copy. */ public AttributeInfo copy(ConstPool newCp, Map classnames) { Copier copier = new Copier(info, constPool, newCp, classnames); try { copier.annotationArray(); return new TypeAnnotationsAttribute(newCp, getName(), copier.close()); } catch (Exception e) { throw new RuntimeException(e); } } /** * @param oldname a JVM class name. * @param newname a JVM class name. */ void renameClass(String oldname, String newname) { HashMap map = new HashMap(); map.put(oldname, newname); renameClass(map); } void renameClass(Map classnames) { Renamer renamer = new Renamer(info, getConstPool(), classnames); try { renamer.annotationArray(); } catch (Exception e) { throw new RuntimeException(e); } } void getRefClasses(Map classnames) { renameClass(classnames); } /** * To visit each elements of the type annotation attribute, * call {@code annotationArray()}. * * @see #annotationArray() */ static class TAWalker extends AnnotationsAttribute.Walker { SubWalker subWalker; TAWalker(byte[] attrInfo) { super(attrInfo); subWalker = new SubWalker(attrInfo); } int annotationArray(int pos, int num) throws Exception { for (int i = 0; i < num; i++) { int targetType = info[pos] & 0xff; pos = subWalker.targetInfo(pos + 1, targetType); pos = subWalker.typePath(pos); pos = annotation(pos); } return pos; } } static class SubWalker { byte[] info; SubWalker(byte[] attrInfo) { info = attrInfo; } final int targetInfo(int pos, int type) throws Exception { switch (type) { case 0x00: case 0x01: { int index = info[pos] & 0xff; typeParameterTarget(pos, type, index); return pos + 1; } case 0x10: { int index = ByteArray.readU16bit(info, pos); supertypeTarget(pos, index); return pos + 2; } case 0x11: case 0x12: { int param = info[pos] & 0xff; int bound = info[pos + 1] & 0xff; typeParameterBoundTarget(pos, type, param, bound); return pos + 2; } case 0x13: case 0x14: case 0x15: emptyTarget(pos, type); return pos; case 0x16: { int index = info[pos] & 0xff; formalParameterTarget(pos, index); return pos + 1; } case 0x17: { int index = ByteArray.readU16bit(info, pos); throwsTarget(pos, index); return pos + 2; } case 0x40: case 0x41: { int len = ByteArray.readU16bit(info, pos); return localvarTarget(pos + 2, type, len); } case 0x42: { int index = ByteArray.readU16bit(info, pos); catchTarget(pos, index); return pos + 2; } case 0x43: case 0x44: case 0x45: case 0x46: { int offset = ByteArray.readU16bit(info, pos); offsetTarget(pos, type, offset); return pos + 2; } case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: { int offset = ByteArray.readU16bit(info, pos); int index = info[pos + 2] & 0xff; typeArgumentTarget(pos, type, offset, index); return pos + 3; } default: throw new RuntimeException("invalid target type: " + type); } } void typeParameterTarget(int pos, int targetType, int typeParameterIndex) throws Exception {} void supertypeTarget(int pos, int superTypeIndex) throws Exception {} void typeParameterBoundTarget(int pos, int targetType, int typeParameterIndex, int boundIndex) throws Exception {} void emptyTarget(int pos, int targetType) throws Exception {} void formalParameterTarget(int pos, int formalParameterIndex) throws Exception {} void throwsTarget(int pos, int throwsTypeIndex) throws Exception {} int localvarTarget(int pos, int targetType, int tableLength) throws Exception { for (int i = 0; i < tableLength; i++) { int start = ByteArray.readU16bit(info, pos); int length = ByteArray.readU16bit(info, pos + 2); int index = ByteArray.readU16bit(info, pos + 4); localvarTarget(pos, targetType, start, length, index); pos += 6; } return pos; } void localvarTarget(int pos, int targetType, int startPc, int length, int index) throws Exception {} void catchTarget(int pos, int exceptionTableIndex) throws Exception {} void offsetTarget(int pos, int targetType, int offset) throws Exception {} void typeArgumentTarget(int pos, int targetType, int offset, int typeArgumentIndex) throws Exception {} final int typePath(int pos) throws Exception { int len = info[pos++] & 0xff; return typePath(pos, len); } int typePath(int pos, int pathLength) throws Exception { for (int i = 0; i < pathLength; i++) { int kind = info[pos] & 0xff; int index = info[pos + 1] & 0xff; typePath(pos, kind, index); pos += 2; } return pos; } void typePath(int pos, int typePathKind, int typeArgumentIndex) throws Exception {} } static class Renamer extends AnnotationsAttribute.Renamer { SubWalker sub; Renamer(byte[] attrInfo, ConstPool cp, Map map) { super(attrInfo, cp, map); sub = new SubWalker(attrInfo); } int annotationArray(int pos, int num) throws Exception { for (int i = 0; i < num; i++) { int targetType = info[pos] & 0xff; pos = sub.targetInfo(pos + 1, targetType); pos = sub.typePath(pos); pos = annotation(pos); } return pos; } } static class Copier extends AnnotationsAttribute.Copier { SubCopier sub; Copier(byte[] attrInfo, ConstPool src, ConstPool dest, Map map) { super(attrInfo, src, dest, map, false); TypeAnnotationsWriter w = new TypeAnnotationsWriter(output, dest); writer = w; sub = new SubCopier(attrInfo, src, dest, map, w); } int annotationArray(int pos, int num) throws Exception { writer.numAnnotations(num); for (int i = 0; i < num; i++) { int targetType = info[pos] & 0xff; pos = sub.targetInfo(pos + 1, targetType); pos = sub.typePath(pos); pos = annotation(pos); } return pos; } } static class SubCopier extends SubWalker { ConstPool srcPool, destPool; Map classnames; TypeAnnotationsWriter writer; SubCopier(byte[] attrInfo, ConstPool src, ConstPool dest, Map map, TypeAnnotationsWriter w) { super(attrInfo); srcPool = src; destPool = dest; classnames = map; writer = w; } void typeParameterTarget(int pos, int targetType, int typeParameterIndex) throws Exception { writer.typeParameterTarget(targetType, typeParameterIndex); } void supertypeTarget(int pos, int superTypeIndex) throws Exception { writer.supertypeTarget(superTypeIndex); } void typeParameterBoundTarget(int pos, int targetType, int typeParameterIndex, int boundIndex) throws Exception { writer.typeParameterBoundTarget(targetType, typeParameterIndex, boundIndex); } void emptyTarget(int pos, int targetType) throws Exception { writer.emptyTarget(targetType); } void formalParameterTarget(int pos, int formalParameterIndex) throws Exception { writer.formalParameterTarget(formalParameterIndex); } void throwsTarget(int pos, int throwsTypeIndex) throws Exception { writer.throwsTarget(throwsTypeIndex); } int localvarTarget(int pos, int targetType, int tableLength) throws Exception { writer.localVarTarget(targetType, tableLength); return super.localvarTarget(pos, targetType, tableLength); } void localvarTarget(int pos, int targetType, int startPc, int length, int index) throws Exception { writer.localVarTargetTable(startPc, length, index); } void catchTarget(int pos, int exceptionTableIndex) throws Exception { writer.catchTarget(exceptionTableIndex); } void offsetTarget(int pos, int targetType, int offset) throws Exception { writer.offsetTarget(targetType, offset); } void typeArgumentTarget(int pos, int targetType, int offset, int typeArgumentIndex) throws Exception { writer.typeArgumentTarget(targetType, offset, typeArgumentIndex); } int typePath(int pos, int pathLength) throws Exception { writer.typePath(pathLength); return super.typePath(pos, pathLength); } void typePath(int pos, int typePathKind, int typeArgumentIndex) throws Exception { writer.typePathPath(typePathKind, typeArgumentIndex); } } }