@@ -284,7 +284,7 @@ see javassist.Dump. | |||
<p>-version 3.19 | |||
<ul> | |||
<li>JIRA JASSIST-158, 205, 206, 207, 208, 209, 211, 212, 216, 220, 223, 224, | |||
227, 230, 234, 235, 236, 237. | |||
227, 230, 234, 235, 236, 237, 238, 240. | |||
</ul> | |||
</p> | |||
@@ -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; |
@@ -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); |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
@@ -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()); | |||
} | |||
} |
@@ -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; } | |||
} |
@@ -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 {} |