aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorchibash <chiba@javassist.org>2015-01-06 01:17:34 +0900
committerchibash <chiba@javassist.org>2015-01-06 01:17:34 +0900
commitec3afdfb5d58b98ae8091d59f84d0d2f7f97a725 (patch)
treef1b1544f83f34fba403281e09c0a32a520286214 /src
parentf2093c28be24336593e1ebd9c2c633ee0f8c5b5c (diff)
downloadjavassist-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.java32
-rw-r--r--src/main/javassist/bytecode/AttributeInfo.java100
-rw-r--r--src/main/javassist/bytecode/TypeAnnotationsAttribute.java358
-rw-r--r--src/main/javassist/bytecode/annotation/AnnotationsWriter.java62
-rw-r--r--src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java172
-rw-r--r--src/test/javassist/JvstTest4.java18
-rw-r--r--src/test/javassist/JvstTest5.java13
-rw-r--r--src/test/test5/TypeAnno.java30
-rw-r--r--src/test/test5/TypeAnnoA.java10
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 {}