diff options
author | chibash <chiba@javassist.org> | 2015-01-06 01:17:34 +0900 |
---|---|---|
committer | chibash <chiba@javassist.org> | 2015-01-06 01:17:34 +0900 |
commit | ec3afdfb5d58b98ae8091d59f84d0d2f7f97a725 (patch) | |
tree | f1b1544f83f34fba403281e09c0a32a520286214 /src | |
parent | f2093c28be24336593e1ebd9c2c633ee0f8c5b5c (diff) | |
download | javassist-ec3afdfb5d58b98ae8091d59f84d0d2f7f97a725.tar.gz javassist-ec3afdfb5d58b98ae8091d59f84d0d2f7f97a725.zip |
fixed JASSIST-240. support for Runtime[In]VisibleTypeAnnotations
Diffstat (limited to 'src')
-rw-r--r-- | src/main/javassist/bytecode/AnnotationsAttribute.java | 32 | ||||
-rw-r--r-- | src/main/javassist/bytecode/AttributeInfo.java | 100 | ||||
-rw-r--r-- | src/main/javassist/bytecode/TypeAnnotationsAttribute.java | 358 | ||||
-rw-r--r-- | src/main/javassist/bytecode/annotation/AnnotationsWriter.java | 62 | ||||
-rw-r--r-- | src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java | 172 | ||||
-rw-r--r-- | src/test/javassist/JvstTest4.java | 18 | ||||
-rw-r--r-- | src/test/javassist/JvstTest5.java | 13 | ||||
-rw-r--r-- | src/test/test5/TypeAnno.java | 30 | ||||
-rw-r--r-- | src/test/test5/TypeAnnoA.java | 10 |
9 files changed, 711 insertions, 84 deletions
diff --git a/src/main/javassist/bytecode/AnnotationsAttribute.java b/src/main/javassist/bytecode/AnnotationsAttribute.java index f5dc581a..38b88eaa 100644 --- a/src/main/javassist/bytecode/AnnotationsAttribute.java +++ b/src/main/javassist/bytecode/AnnotationsAttribute.java @@ -350,15 +350,24 @@ public class AnnotationsAttribute extends AttributeInfo { return pos; } + /** + * {@code element_value_paris} + */ final int memberValuePair(int pos) throws Exception { int nameIndex = ByteArray.readU16bit(info, pos); return memberValuePair(pos + 2, nameIndex); } + /** + * {@code element_value_paris[]} + */ int memberValuePair(int pos, int nameIndex) throws Exception { return memberValue(pos); } + /** + * {@code element_value} + */ final int memberValue(int pos) throws Exception { int tag = info[pos] & 0xff; if (tag == 'e') { @@ -385,18 +394,33 @@ public class AnnotationsAttribute extends AttributeInfo { } } + /** + * {@code const_value_index} + */ void constValueMember(int tag, int index) throws Exception {} + /** + * {@code enum_const_value} + */ void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) throws Exception { } + /** + * {@code class_info_index} + */ void classMemberValue(int pos, int index) throws Exception {} + /** + * {@code annotation_value} + */ int annotationMemberValue(int pos) throws Exception { return annotation(pos); } + /** + * {@code array_value} + */ int arrayMemberValue(int pos, int num) throws Exception { for (int i = 0; i < num; ++i) { pos = memberValue(pos); @@ -470,9 +494,15 @@ public class AnnotationsAttribute extends AttributeInfo { * It can be null. */ Copier(byte[] info, ConstPool src, ConstPool dest, Map map) { + this(info, src, dest, map, true); + } + + Copier(byte[] info, ConstPool src, ConstPool dest, Map map, boolean makeWriter) { super(info); output = new ByteArrayOutputStream(); - writer = new AnnotationsWriter(output, dest); + if (makeWriter) + writer = new AnnotationsWriter(output, dest); + srcPool = src; destPool = dest; classnames = map; diff --git a/src/main/javassist/bytecode/AttributeInfo.java b/src/main/javassist/bytecode/AttributeInfo.java index 7dee7829..5f26d5c9 100644 --- a/src/main/javassist/bytecode/AttributeInfo.java +++ b/src/main/javassist/bytecode/AttributeInfo.java @@ -74,53 +74,65 @@ public class AttributeInfo { { int name = in.readUnsignedShort(); String nameStr = cp.getUtf8Info(name); - if (nameStr.charAt(0) < 'L') { - if (nameStr.equals(AnnotationDefaultAttribute.tag)) - return new AnnotationDefaultAttribute(cp, name, in); - else if (nameStr.equals(BootstrapMethodsAttribute.tag)) - return new BootstrapMethodsAttribute(cp, name, in); - else if (nameStr.equals(CodeAttribute.tag)) - return new CodeAttribute(cp, name, in); - else if (nameStr.equals(ConstantAttribute.tag)) - return new ConstantAttribute(cp, name, in); - else if (nameStr.equals(DeprecatedAttribute.tag)) - return new DeprecatedAttribute(cp, name, in); - else if (nameStr.equals(EnclosingMethodAttribute.tag)) - return new EnclosingMethodAttribute(cp, name, in); - else if (nameStr.equals(ExceptionsAttribute.tag)) - return new ExceptionsAttribute(cp, name, in); - else if (nameStr.equals(InnerClassesAttribute.tag)) - return new InnerClassesAttribute(cp, name, in); + char first = nameStr.charAt(0); + if (first < 'M') { + if (first < 'E') { + if (nameStr.equals(AnnotationDefaultAttribute.tag)) + return new AnnotationDefaultAttribute(cp, name, in); + else if (nameStr.equals(BootstrapMethodsAttribute.tag)) + return new BootstrapMethodsAttribute(cp, name, in); + else if (nameStr.equals(CodeAttribute.tag)) + return new CodeAttribute(cp, name, in); + else if (nameStr.equals(ConstantAttribute.tag)) + return new ConstantAttribute(cp, name, in); + else if (nameStr.equals(DeprecatedAttribute.tag)) + return new DeprecatedAttribute(cp, name, in); + } + else { + if (nameStr.equals(EnclosingMethodAttribute.tag)) + return new EnclosingMethodAttribute(cp, name, in); + else if (nameStr.equals(ExceptionsAttribute.tag)) + return new ExceptionsAttribute(cp, name, in); + else if (nameStr.equals(InnerClassesAttribute.tag)) + return new InnerClassesAttribute(cp, name, in); + else if (nameStr.equals(LineNumberAttribute.tag)) + return new LineNumberAttribute(cp, name, in); + else if (nameStr.equals(LocalVariableAttribute.tag)) + return new LocalVariableAttribute(cp, name, in); + else if (nameStr.equals(LocalVariableTypeAttribute.tag)) + return new LocalVariableTypeAttribute(cp, name, in); + } } else { - /* Note that the names of Annotations attributes begin with 'R'. - */ - if (nameStr.equals(LineNumberAttribute.tag)) - return new LineNumberAttribute(cp, name, in); - else if (nameStr.equals(LocalVariableAttribute.tag)) - return new LocalVariableAttribute(cp, name, in); - else if (nameStr.equals(LocalVariableTypeAttribute.tag)) - return new LocalVariableTypeAttribute(cp, name, in); - else if (nameStr.equals(MethodParametersAttribute.tag)) - return new MethodParametersAttribute(cp, name, in); - else if (nameStr.equals(AnnotationsAttribute.visibleTag) - || nameStr.equals(AnnotationsAttribute.invisibleTag)) { - // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations - return new AnnotationsAttribute(cp, name, in); + if (first < 'S') { + /* Note that the names of Annotations attributes begin with 'R'. + */ + if (nameStr.equals(MethodParametersAttribute.tag)) + return new MethodParametersAttribute(cp, name, in); + else if (nameStr.equals(AnnotationsAttribute.visibleTag) + || nameStr.equals(AnnotationsAttribute.invisibleTag)) { + // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations + return new AnnotationsAttribute(cp, name, in); + } + else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag) + || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag)) + return new ParameterAnnotationsAttribute(cp, name, in); + else if (nameStr.equals(TypeAnnotationsAttribute.visibleTag) + || nameStr.equals(TypeAnnotationsAttribute.invisibleTag)) + return new TypeAnnotationsAttribute(cp, name, in); + } + else { + if (nameStr.equals(SignatureAttribute.tag)) + return new SignatureAttribute(cp, name, in); + else if (nameStr.equals(SourceFileAttribute.tag)) + return new SourceFileAttribute(cp, name, in); + else if (nameStr.equals(SyntheticAttribute.tag)) + return new SyntheticAttribute(cp, name, in); + else if (nameStr.equals(StackMap.tag)) + return new StackMap(cp, name, in); + else if (nameStr.equals(StackMapTable.tag)) + return new StackMapTable(cp, name, in); } - else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag) - || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag)) - return new ParameterAnnotationsAttribute(cp, name, in); - else if (nameStr.equals(SignatureAttribute.tag)) - return new SignatureAttribute(cp, name, in); - else if (nameStr.equals(SourceFileAttribute.tag)) - return new SourceFileAttribute(cp, name, in); - else if (nameStr.equals(SyntheticAttribute.tag)) - return new SyntheticAttribute(cp, name, in); - else if (nameStr.equals(StackMap.tag)) - return new StackMap(cp, name, in); - else if (nameStr.equals(StackMapTable.tag)) - return new StackMapTable(cp, name, in); } return new AttributeInfo(cp, name, in); diff --git a/src/main/javassist/bytecode/TypeAnnotationsAttribute.java b/src/main/javassist/bytecode/TypeAnnotationsAttribute.java new file mode 100644 index 00000000..67706208 --- /dev/null +++ b/src/main/javassist/bytecode/TypeAnnotationsAttribute.java @@ -0,0 +1,358 @@ +package javassist.bytecode; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javassist.bytecode.annotation.TypeAnnotationsWriter; + +/** + * A class representing + * {@code RuntimeVisibleTypeAnnotations} attribute and + * {@code RuntimeInvisibleTypeAnnotations} attribute. + */ +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); + } + } +} diff --git a/src/main/javassist/bytecode/annotation/AnnotationsWriter.java b/src/main/javassist/bytecode/annotation/AnnotationsWriter.java index 5a510a4c..b366acb8 100644 --- a/src/main/javassist/bytecode/annotation/AnnotationsWriter.java +++ b/src/main/javassist/bytecode/annotation/AnnotationsWriter.java @@ -35,9 +35,9 @@ import javassist.bytecode.ConstPool; * * writer.numAnnotations(1); * writer.annotation("Author", 2); - * writer.memberValuePair("name"); + * writer.memberValuePair("name"); // element_value_pair * writer.constValueIndex("chiba"); - * writer.memberValuePair("address"); + * writer.memberValuePair("address"); // element_value_pair * writer.constValueIndex("tokyo"); * * writer.close(); @@ -58,7 +58,7 @@ import javassist.bytecode.ConstPool; * @see javassist.bytecode.ParameterAnnotationsAttribute */ public class AnnotationsWriter { - private OutputStream output; + protected OutputStream output; private ConstPool pool; /** @@ -113,7 +113,7 @@ public class AnnotationsWriter { * calls to <code>memberValuePair()</code>. * * @param type the annotation interface name. - * @param numMemberValuePairs <code>num_member_value_pairs</code> + * @param numMemberValuePairs <code>num_element_value_pairs</code> * in <code>annotation</code>. */ public void annotation(String type, int numMemberValuePairs) @@ -128,7 +128,7 @@ public class AnnotationsWriter { * calls to <code>memberValuePair()</code>. * * @param typeIndex <code>type_index</code> in <code>annotation</code>. - * @param numMemberValuePairs <code>num_member_value_pairs</code> + * @param numMemberValuePairs <code>num_element_value_pairs</code> * in <code>annotation</code>. */ public void annotation(int typeIndex, int numMemberValuePairs) @@ -139,27 +139,27 @@ public class AnnotationsWriter { } /** - * Writes an element of a <code>member_value_pairs</code> array + * Writes an element of a <code>element_value_pairs</code> array * in <code>annotation</code>. * This method must be followed by a * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, * etc. * - * @param memberName the name of the annotation type member. + * @param memberName the element name. */ public void memberValuePair(String memberName) throws IOException { memberValuePair(pool.addUtf8Info(memberName)); } /** - * Writes an element of a <code>member_value_pairs</code> array + * Writes an element of a <code>element_value_pairs</code> array * in <code>annotation</code>. * This method must be followed by a * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, * etc. * - * @param memberNameIndex <code>member_name_index</code> - * in <code>member_value_pairs</code> array. + * @param memberNameIndex <code>element_name_index</code> + * in <code>element_value_pairs</code> array. */ public void memberValuePair(int memberNameIndex) throws IOException { write16bit(memberNameIndex); @@ -167,7 +167,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -177,7 +177,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -187,7 +187,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -197,7 +197,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -207,7 +207,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -217,7 +217,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -227,7 +227,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -237,7 +237,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -247,7 +247,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param value the constant value. */ @@ -257,11 +257,11 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * - * @param tag <code>tag</code> in <code>member_value</code>. + * @param tag <code>tag</code> in <code>element_value</code>. * @param index <code>const_value_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. */ public void constValueIndex(int tag, int index) throws IOException @@ -272,7 +272,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>enum_const_value</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param typeName the type name of the enum constant. * @param constName the simple name of the enum constant. @@ -286,12 +286,12 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>enum_const_value</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param typeNameIndex <code>type_name_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * @param constNameIndex <code>const_name_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. */ public void enumConstValue(int typeNameIndex, int constNameIndex) throws IOException @@ -303,7 +303,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>class_info_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param name the class name. */ @@ -313,7 +313,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>class_info_index</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * * @param index <code>class_info_index</code> */ @@ -324,7 +324,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>annotation_value</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * This method must be followed by a call to <code>annotation()</code>. */ public void annotationValue() throws IOException { @@ -333,7 +333,7 @@ public class AnnotationsWriter { /** * Writes <code>tag</code> and <code>array_value</code> - * in <code>member_value</code>. + * in <code>element_value</code>. * This method must be followed by <code>numValues</code> calls * to <code>constValueIndex()</code>, <code>enumConstValue()</code>, * etc. @@ -346,7 +346,7 @@ public class AnnotationsWriter { write16bit(numValues); } - private void write16bit(int value) throws IOException { + protected void write16bit(int value) throws IOException { byte[] buf = new byte[2]; ByteArray.write16bit(value, buf, 0); output.write(buf); diff --git a/src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java b/src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java new file mode 100644 index 00000000..a1932e05 --- /dev/null +++ b/src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java @@ -0,0 +1,172 @@ +package javassist.bytecode.annotation; + +import java.io.IOException; +import java.io.OutputStream; + +import javassist.bytecode.ConstPool; + +/** + * A convenience class for constructing a + * {@code ..TypeAnnotations_attribute}. + * See the source code of the {@link javassist.bytecode.TypeAnnotationsAttribute} class. + */ +public class TypeAnnotationsWriter extends AnnotationsWriter { + /** + * Constructs with the given output stream. + * + * @param os the output stream. + * @param cp the constant pool. + */ + public TypeAnnotationsWriter(OutputStream os, ConstPool cp) { + super(os, cp); + } + + /** + * Writes {@code num_annotations} in + * {@code Runtime(In)VisibleTypeAnnotations_attribute}. + * It must be followed by {@code num} instances of {@code type_annotation}. + */ + public void numAnnotations(int num) throws IOException { + super.numAnnotations(num); + } + + /** + * Writes {@code target_type} and {@code type_parameter_target} + * of {@code target_info} union. + */ + public void typeParameterTarget(int targetType, int typeParameterIndex) + throws IOException + { + output.write(targetType); + output.write(typeParameterIndex); + } + + /** + * Writes {@code target_type} and {@code supertype_target} + * of {@code target_info} union. + */ + public void supertypeTarget(int supertypeIndex) + throws IOException + { + output.write(0x10); + write16bit(supertypeIndex); + } + + /** + * Writes {@code target_type} and {@code type_parameter_bound_target} + * of {@code target_info} union. + */ + public void typeParameterBoundTarget(int targetType, int typeParameterIndex, int boundIndex) + throws IOException + { + output.write(targetType); + output.write(typeParameterIndex); + output.write(boundIndex); + } + + /** + * Writes {@code target_type} and {@code empty_target} + * of {@code target_info} union. + */ + public void emptyTarget(int targetType) throws IOException { + output.write(targetType); + } + + /** + * Writes {@code target_type} and {@code type_parameter_target} + * of {@code target_info} union. + */ + public void formalParameterTarget(int formalParameterIndex) + throws IOException + { + output.write(0x16); + output.write(formalParameterIndex); + } + + /** + * Writes {@code target_type} and {@code throws_target} + * of {@code target_info} union. + */ + public void throwsTarget(int throwsTypeIndex) + throws IOException + { + output.write(0x17); + write16bit(throwsTypeIndex); + } + + /** + * Writes {@code target_type} and {@code localvar_target} + * of {@code target_info} union. + * It must be followed by {@code tableLength} calls + * to {@code localVarTargetTable}. + */ + public void localVarTarget(int targetType, int tableLength) + throws IOException + { + output.write(targetType); + write16bit(tableLength); + } + + /** + * Writes an element of {@code table[]} of {@code localvar_target} + * of {@code target_info} union. + */ + public void localVarTargetTable(int startPc, int length, int index) + throws IOException + { + write16bit(startPc); + write16bit(length); + write16bit(index); + } + + /** + * Writes {@code target_type} and {@code catch_target} + * of {@code target_info} union. + */ + public void catchTarget(int exceptionTableIndex) + throws IOException + { + output.write(0x42); + write16bit(exceptionTableIndex); + } + + /** + * Writes {@code target_type} and {@code offset_target} + * of {@code target_info} union. + */ + public void offsetTarget(int targetType, int offset) + throws IOException + { + output.write(targetType); + write16bit(offset); + } + + /** + * Writes {@code target_type} and {@code type_argument_target} + * of {@code target_info} union. + */ + public void typeArgumentTarget(int targetType, int offset, int type_argument_index) + throws IOException + { + output.write(targetType); + write16bit(offset); + output.write(type_argument_index); + } + + /** + * Writes {@code path_length} of {@code type_path}. + */ + public void typePath(int pathLength) throws IOException { + output.write(pathLength); + } + + /** + * Writes an element of {@code path[]} of {@code type_path}. + */ + public void typePathPath(int typePathKind, int typeArgumentIndex) + throws IOException + { + output.write(typePathKind); + output.write(typeArgumentIndex); + } +} diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java index d5616056..c39f6700 100644 --- a/src/test/javassist/JvstTest4.java +++ b/src/test/javassist/JvstTest4.java @@ -606,10 +606,10 @@ public class JvstTest4 extends JvstTestRoot { assertEquals(packageName, obj.getClass().getPackage().getName()); } - public static final String BASE_PATH="../"; - public static final String JAVASSIST_JAR=BASE_PATH+"javassist.jar"; - public static final String CLASSES_FOLDER=BASE_PATH+"build/classes"; - public static final String TEST_CLASSES_FOLDER=BASE_PATH+"build/test-classes"; + public static final String BASE_PATH = "../"; + public static final String JAVASSIST_JAR = BASE_PATH + "javassist.jar"; + public static final String CLASSES_FOLDER = BASE_PATH + "build/classes"; + public static final String TEST_CLASSES_FOLDER = BASE_PATH + "build/test-classes"; public static class Inner1 { public static int get() { @@ -661,8 +661,8 @@ public class JvstTest4 extends JvstTestRoot { long t2 = endTime2 - endTime; long t3 = endTime3 - endTime2; System.out.println("JIRA150: " + t1 + ", " + t2 + ", " + t3); - assertTrue("performance test (the next try may succeed): " + t1 + "/ 5 < " + t2, - t2 < t1 * 5); + assertTrue("performance test (the next try may succeed): " + t1 + "/ 6 < " + t2, + t2 < t1 * 6); assertTrue("", t3 < t1 * 3); } @@ -691,15 +691,17 @@ public class JvstTest4 extends JvstTestRoot { } // try to run garbage collection. + int[][] mem = new int[100][]; int[] large; for (int i = 0; i < 100; i++) { large = new int[1000000]; - large[large.length - 2] = 9; + large[large.length - 2] = 9 + i; + mem[i] = large; } System.gc(); System.gc(); int size = javassist.compiler.MemberResolver.getInvalidMapSize(); - System.out.println("JIRA150b " + size); + System.out.println("JIRA150b " + size + " " + mem[mem.length - 1][mem[0].length - 2]); assertTrue("JIRA150b size: " + origSize + " " + size, size < origSize + N); } diff --git a/src/test/javassist/JvstTest5.java b/src/test/javassist/JvstTest5.java index 32cebbe2..becd5c59 100644 --- a/src/test/javassist/JvstTest5.java +++ b/src/test/javassist/JvstTest5.java @@ -1,5 +1,8 @@ package javassist; +import java.lang.annotation.Annotation; +import java.lang.reflect.TypeVariable; + public class JvstTest5 extends JvstTestRoot { public JvstTest5(String name) { super(name); @@ -31,4 +34,14 @@ public class JvstTest5 extends JvstTestRoot { assertEquals(10, invoke(obj, "run2")); assertEquals(10, invoke(obj, "run3")); } + + public void testTypeAnno() throws Exception { + CtClass cc = sloader.get("test5.TypeAnno"); + cc.getClassFile().compact(); + cc.writeFile(); + Object obj = make(cc.getName()); + TypeVariable<?> t = obj.getClass().getTypeParameters()[0]; + Annotation[] annos = t.getAnnotations(); + assertEquals("@test5.TypeAnnoA()", annos[0].toString()); + } } diff --git a/src/test/test5/TypeAnno.java b/src/test/test5/TypeAnno.java new file mode 100644 index 00000000..a24d4008 --- /dev/null +++ b/src/test/test5/TypeAnno.java @@ -0,0 +1,30 @@ +package test5; + +import java.util.ArrayList; + +class TypeAnnoSuper {} +interface TypeAnnoI {} + +@TypeAnnoA +public class TypeAnno<@TypeAnnoA TT extends @TypeAnnoA String> extends @TypeAnnoA TypeAnnoSuper implements @TypeAnnoA TypeAnnoI { + public @TypeAnnoA String foo(@TypeAnnoA int i) throws @TypeAnnoA Exception { + @TypeAnnoA String s = new @TypeAnnoA String("bar "); + Object t = s; + String ss = (@TypeAnnoA String)t; + ArrayList<@TypeAnnoA String> list = new ArrayList<@TypeAnnoA String>(); + if (list instanceof /* @TypeAnnoA */ java.util.List) + System.out.println("ok"); + + try { + list.add(ss); + } catch (@TypeAnnoA RuntimeException e) {} + return "foo" + list.get(0) + i; + } + + @TypeAnnoA double dvalue; + @TypeAnnoA int ivalue @TypeAnnoA [] @TypeAnnoA [] @TypeAnnoA []; + + <@TypeAnnoA T extends @TypeAnnoA String> T bar(T t) { return t; } + + @TypeAnnoA TT getNull() { return null; } +} diff --git a/src/test/test5/TypeAnnoA.java b/src/test/test5/TypeAnnoA.java new file mode 100644 index 00000000..75267787 --- /dev/null +++ b/src/test/test5/TypeAnnoA.java @@ -0,0 +1,10 @@ +package test5; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TypeAnnoA {} |