From: chibash -version 3.19
Runtime(In)VisibleTypeAnnotations_attribute
.
+ *
+ * @param cp constant pool
+ * @param attrname attribute name (visibleTag
or
+ * invisibleTag
).
+ * @param info the contents of this attribute. It does not
+ * include attribute_name_index
or
+ * attribute_length
.
+ */
+ 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 num_annotations
.
+ */
+ 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 memberValuePair()
.
*
* @param type the annotation interface name.
- * @param numMemberValuePairs num_member_value_pairs
+ * @param numMemberValuePairs num_element_value_pairs
* in annotation
.
*/
public void annotation(String type, int numMemberValuePairs)
@@ -128,7 +128,7 @@ public class AnnotationsWriter {
* calls to memberValuePair()
.
*
* @param typeIndex type_index
in annotation
.
- * @param numMemberValuePairs num_member_value_pairs
+ * @param numMemberValuePairs num_element_value_pairs
* in annotation
.
*/
public void annotation(int typeIndex, int numMemberValuePairs)
@@ -139,27 +139,27 @@ public class AnnotationsWriter {
}
/**
- * Writes an element of a member_value_pairs
array
+ * Writes an element of a element_value_pairs
array
* in annotation
.
* This method must be followed by a
* call to constValueIndex()
, enumConstValue()
,
* 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 member_value_pairs
array
+ * Writes an element of a element_value_pairs
array
* in annotation
.
* This method must be followed by a
* call to constValueIndex()
, enumConstValue()
,
* etc.
*
- * @param memberNameIndex member_name_index
- * in member_value_pairs
array.
+ * @param memberNameIndex element_name_index
+ * in element_value_pairs
array.
*/
public void memberValuePair(int memberNameIndex) throws IOException {
write16bit(memberNameIndex);
@@ -167,7 +167,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -177,7 +177,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -187,7 +187,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -197,7 +197,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -207,7 +207,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -217,7 +217,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -227,7 +227,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -237,7 +237,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -247,7 +247,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
* @param value the constant value.
*/
@@ -257,11 +257,11 @@ public class AnnotationsWriter {
/**
* Writes tag
and const_value_index
- * in member_value
.
+ * in element_value
.
*
- * @param tag tag
in member_value
.
+ * @param tag tag
in element_value
.
* @param index const_value_index
- * in member_value
.
+ * in element_value
.
*/
public void constValueIndex(int tag, int index)
throws IOException
@@ -272,7 +272,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and enum_const_value
- * in member_value
.
+ * in element_value
.
*
* @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 tag
and enum_const_value
- * in member_value
.
+ * in element_value
.
*
* @param typeNameIndex type_name_index
- * in member_value
.
+ * in element_value
.
* @param constNameIndex const_name_index
- * in member_value
.
+ * in element_value
.
*/
public void enumConstValue(int typeNameIndex, int constNameIndex)
throws IOException
@@ -303,7 +303,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and class_info_index
- * in member_value
.
+ * in element_value
.
*
* @param name the class name.
*/
@@ -313,7 +313,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and class_info_index
- * in member_value
.
+ * in element_value
.
*
* @param index class_info_index
*/
@@ -324,7 +324,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and annotation_value
- * in member_value
.
+ * in element_value
.
* This method must be followed by a call to annotation()
.
*/
public void annotationValue() throws IOException {
@@ -333,7 +333,7 @@ public class AnnotationsWriter {
/**
* Writes tag
and array_value
- * in member_value
.
+ * in element_value
.
* This method must be followed by numValues
calls
* to constValueIndex()
, enumConstValue()
,
* 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 {}