<p>-version 3.19 | <p>-version 3.19 | ||||
<ul> | <ul> | ||||
<li>JIRA JASSIST-158, 205, 206, 207, 208, 209, 211, 212, 216, 220, 223, 224, | <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> | </ul> | ||||
</p> | </p> | ||||
return pos; | return pos; | ||||
} | } | ||||
/** | |||||
* {@code element_value_paris} | |||||
*/ | |||||
final int memberValuePair(int pos) throws Exception { | final int memberValuePair(int pos) throws Exception { | ||||
int nameIndex = ByteArray.readU16bit(info, pos); | int nameIndex = ByteArray.readU16bit(info, pos); | ||||
return memberValuePair(pos + 2, nameIndex); | return memberValuePair(pos + 2, nameIndex); | ||||
} | } | ||||
/** | |||||
* {@code element_value_paris[]} | |||||
*/ | |||||
int memberValuePair(int pos, int nameIndex) throws Exception { | int memberValuePair(int pos, int nameIndex) throws Exception { | ||||
return memberValue(pos); | return memberValue(pos); | ||||
} | } | ||||
/** | |||||
* {@code element_value} | |||||
*/ | |||||
final int memberValue(int pos) throws Exception { | final int memberValue(int pos) throws Exception { | ||||
int tag = info[pos] & 0xff; | int tag = info[pos] & 0xff; | ||||
if (tag == 'e') { | if (tag == 'e') { | ||||
} | } | ||||
} | } | ||||
/** | |||||
* {@code const_value_index} | |||||
*/ | |||||
void constValueMember(int tag, int index) throws Exception {} | void constValueMember(int tag, int index) throws Exception {} | ||||
/** | |||||
* {@code enum_const_value} | |||||
*/ | |||||
void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) | void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) | ||||
throws Exception { | throws Exception { | ||||
} | } | ||||
/** | |||||
* {@code class_info_index} | |||||
*/ | |||||
void classMemberValue(int pos, int index) throws Exception {} | void classMemberValue(int pos, int index) throws Exception {} | ||||
/** | |||||
* {@code annotation_value} | |||||
*/ | |||||
int annotationMemberValue(int pos) throws Exception { | int annotationMemberValue(int pos) throws Exception { | ||||
return annotation(pos); | return annotation(pos); | ||||
} | } | ||||
/** | |||||
* {@code array_value} | |||||
*/ | |||||
int arrayMemberValue(int pos, int num) throws Exception { | int arrayMemberValue(int pos, int num) throws Exception { | ||||
for (int i = 0; i < num; ++i) { | for (int i = 0; i < num; ++i) { | ||||
pos = memberValue(pos); | pos = memberValue(pos); | ||||
* It can be null. | * It can be null. | ||||
*/ | */ | ||||
Copier(byte[] info, ConstPool src, ConstPool dest, Map map) { | 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); | super(info); | ||||
output = new ByteArrayOutputStream(); | output = new ByteArrayOutputStream(); | ||||
writer = new AnnotationsWriter(output, dest); | |||||
if (makeWriter) | |||||
writer = new AnnotationsWriter(output, dest); | |||||
srcPool = src; | srcPool = src; | ||||
destPool = dest; | destPool = dest; | ||||
classnames = map; | classnames = map; |
{ | { | ||||
int name = in.readUnsignedShort(); | int name = in.readUnsignedShort(); | ||||
String nameStr = cp.getUtf8Info(name); | 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 { | 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); | return new AttributeInfo(cp, name, in); |
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); | |||||
} | |||||
} | |||||
} |
* | * | ||||
* writer.numAnnotations(1); | * writer.numAnnotations(1); | ||||
* writer.annotation("Author", 2); | * writer.annotation("Author", 2); | ||||
* writer.memberValuePair("name"); | |||||
* writer.memberValuePair("name"); // element_value_pair | |||||
* writer.constValueIndex("chiba"); | * writer.constValueIndex("chiba"); | ||||
* writer.memberValuePair("address"); | |||||
* writer.memberValuePair("address"); // element_value_pair | |||||
* writer.constValueIndex("tokyo"); | * writer.constValueIndex("tokyo"); | ||||
* | * | ||||
* writer.close(); | * writer.close(); | ||||
* @see javassist.bytecode.ParameterAnnotationsAttribute | * @see javassist.bytecode.ParameterAnnotationsAttribute | ||||
*/ | */ | ||||
public class AnnotationsWriter { | public class AnnotationsWriter { | ||||
private OutputStream output; | |||||
protected OutputStream output; | |||||
private ConstPool pool; | private ConstPool pool; | ||||
/** | /** | ||||
* calls to <code>memberValuePair()</code>. | * calls to <code>memberValuePair()</code>. | ||||
* | * | ||||
* @param type the annotation interface name. | * @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>. | * in <code>annotation</code>. | ||||
*/ | */ | ||||
public void annotation(String type, int numMemberValuePairs) | public void annotation(String type, int numMemberValuePairs) | ||||
* calls to <code>memberValuePair()</code>. | * calls to <code>memberValuePair()</code>. | ||||
* | * | ||||
* @param typeIndex <code>type_index</code> in <code>annotation</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>. | * in <code>annotation</code>. | ||||
*/ | */ | ||||
public void annotation(int typeIndex, int numMemberValuePairs) | public void annotation(int typeIndex, int numMemberValuePairs) | ||||
} | } | ||||
/** | /** | ||||
* 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>. | * in <code>annotation</code>. | ||||
* This method must be followed by a | * This method must be followed by a | ||||
* call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, | * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, | ||||
* etc. | * etc. | ||||
* | * | ||||
* @param memberName the name of the annotation type member. | |||||
* @param memberName the element name. | |||||
*/ | */ | ||||
public void memberValuePair(String memberName) throws IOException { | public void memberValuePair(String memberName) throws IOException { | ||||
memberValuePair(pool.addUtf8Info(memberName)); | 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>. | * in <code>annotation</code>. | ||||
* This method must be followed by a | * This method must be followed by a | ||||
* call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, | * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, | ||||
* etc. | * 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 { | public void memberValuePair(int memberNameIndex) throws IOException { | ||||
write16bit(memberNameIndex); | write16bit(memberNameIndex); | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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. | * @param value the constant value. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>const_value_index</code> | * 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> | * @param index <code>const_value_index</code> | ||||
* in <code>member_value</code>. | |||||
* in <code>element_value</code>. | |||||
*/ | */ | ||||
public void constValueIndex(int tag, int index) | public void constValueIndex(int tag, int index) | ||||
throws IOException | throws IOException | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>enum_const_value</code> | * 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 typeName the type name of the enum constant. | ||||
* @param constName the simple name of the enum constant. | * @param constName the simple name of the enum constant. | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>enum_const_value</code> | * 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> | * @param typeNameIndex <code>type_name_index</code> | ||||
* in <code>member_value</code>. | |||||
* in <code>element_value</code>. | |||||
* @param constNameIndex <code>const_name_index</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) | public void enumConstValue(int typeNameIndex, int constNameIndex) | ||||
throws IOException | throws IOException | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>class_info_index</code> | * 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. | * @param name the class name. | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>class_info_index</code> | * 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> | * @param index <code>class_info_index</code> | ||||
*/ | */ | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>annotation_value</code> | * 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>. | * This method must be followed by a call to <code>annotation()</code>. | ||||
*/ | */ | ||||
public void annotationValue() throws IOException { | public void annotationValue() throws IOException { | ||||
/** | /** | ||||
* Writes <code>tag</code> and <code>array_value</code> | * 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 | * This method must be followed by <code>numValues</code> calls | ||||
* to <code>constValueIndex()</code>, <code>enumConstValue()</code>, | * to <code>constValueIndex()</code>, <code>enumConstValue()</code>, | ||||
* etc. | * etc. | ||||
write16bit(numValues); | write16bit(numValues); | ||||
} | } | ||||
private void write16bit(int value) throws IOException { | |||||
protected void write16bit(int value) throws IOException { | |||||
byte[] buf = new byte[2]; | byte[] buf = new byte[2]; | ||||
ByteArray.write16bit(value, buf, 0); | ByteArray.write16bit(value, buf, 0); | ||||
output.write(buf); | output.write(buf); |
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); | |||||
} | |||||
} |
assertEquals(packageName, obj.getClass().getPackage().getName()); | 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 class Inner1 { | ||||
public static int get() { | public static int get() { | ||||
long t2 = endTime2 - endTime; | long t2 = endTime2 - endTime; | ||||
long t3 = endTime3 - endTime2; | long t3 = endTime3 - endTime2; | ||||
System.out.println("JIRA150: " + t1 + ", " + t2 + ", " + t3); | 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); | assertTrue("", t3 < t1 * 3); | ||||
} | } | ||||
} | } | ||||
// try to run garbage collection. | // try to run garbage collection. | ||||
int[][] mem = new int[100][]; | |||||
int[] large; | int[] large; | ||||
for (int i = 0; i < 100; i++) { | for (int i = 0; i < 100; i++) { | ||||
large = new int[1000000]; | large = new int[1000000]; | ||||
large[large.length - 2] = 9; | |||||
large[large.length - 2] = 9 + i; | |||||
mem[i] = large; | |||||
} | } | ||||
System.gc(); | System.gc(); | ||||
System.gc(); | System.gc(); | ||||
int size = javassist.compiler.MemberResolver.getInvalidMapSize(); | 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); | assertTrue("JIRA150b size: " + origSize + " " + size, size < origSize + N); | ||||
} | } | ||||
package javassist; | package javassist; | ||||
import java.lang.annotation.Annotation; | |||||
import java.lang.reflect.TypeVariable; | |||||
public class JvstTest5 extends JvstTestRoot { | public class JvstTest5 extends JvstTestRoot { | ||||
public JvstTest5(String name) { | public JvstTest5(String name) { | ||||
super(name); | super(name); | ||||
assertEquals(10, invoke(obj, "run2")); | assertEquals(10, invoke(obj, "run2")); | ||||
assertEquals(10, invoke(obj, "run3")); | 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()); | |||||
} | |||||
} | } |
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; } | |||||
} |
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 {} |