git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@639 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -284,7 +284,7 @@ see javassist.Dump. | |||
<p>-version 3.17 | |||
<ul> | |||
<li>OSGi bundle info is now included in the jar file. | |||
<li>JIRA JASSIST-166, 168 have been fixed. | |||
<li>JIRA JASSIST-166, 168, 170 have been fixed. | |||
</ul> | |||
<p>-version 3.16.1 on March 6, 2012 |
@@ -314,19 +314,43 @@ public abstract class CtBehavior extends CtMember { | |||
* | |||
* <p>Note that the returned string is not the type signature | |||
* contained in the <code>SignatureAttirbute</code>. It is | |||
* a descriptor. To obtain a type signature, call the following | |||
* methods: | |||
* | |||
* <ul><pre>getMethodInfo().getAttribute(SignatureAttribute.tag) | |||
* </pre></ul> | |||
* a descriptor. | |||
* | |||
* @see javassist.bytecode.Descriptor | |||
* @see javassist.bytecode.SignatureAttribute | |||
* @see #getGenericSignature() | |||
*/ | |||
public String getSignature() { | |||
return methodInfo.getDescriptor(); | |||
} | |||
/** | |||
* Returns the generic signature of the method. | |||
* It represents parameter types including type variables. | |||
* | |||
* @see SignatureAttribute#toMethodSignature(String) | |||
* @since 3.17 | |||
*/ | |||
public String getGenericSignature() { | |||
SignatureAttribute sa | |||
= (SignatureAttribute)methodInfo.getAttribute(SignatureAttribute.tag); | |||
return sa == null ? null : sa.getSignature(); | |||
} | |||
/** | |||
* Set the generic signature of the method. | |||
* It represents parameter types including type variables. | |||
* See {@link javassist.CtClass#setGenericSignature(String)} | |||
* for a code sample. | |||
* | |||
* @param sig a new generic signature. | |||
* @see javassist.bytecode.SignatureAttribute.MethodSignature#encode() | |||
* @since 3.17 | |||
*/ | |||
public void setGenericSignature(String sig) { | |||
declaringClass.checkModify(); | |||
methodInfo.addAttribute(new SignatureAttribute(methodInfo.getConstPool(), sig)); | |||
} | |||
/** | |||
* Obtains exceptions that this method/constructor may throw. | |||
* |
@@ -29,6 +29,7 @@ import java.util.Collection; | |||
import javassist.bytecode.ClassFile; | |||
import javassist.bytecode.Descriptor; | |||
import javassist.bytecode.Opcode; | |||
import javassist.bytecode.SignatureAttribute; | |||
import javassist.expr.ExprEditor; | |||
/* Note: | |||
@@ -387,6 +388,89 @@ public abstract class CtClass { | |||
qualifiedName = name; | |||
} | |||
/** | |||
* Returns the generic signature of the class. | |||
* | |||
* <p>The generics of Java is implemented by the erasure technique. | |||
* After compilation, all type parameters are dropped off from the | |||
* main part of a class file. However, for reflection, the type | |||
* parameters are encoded into generic signatures and attached | |||
* to a class file. | |||
* | |||
* @return null if the generic signature is not included. | |||
* @see javassist.bytecode.SignatureAttribute#toClassSignature(String) | |||
* @see CtMember#getGenericSignature() | |||
* @since 3.17 | |||
*/ | |||
public String getGenericSignature() { return null; } | |||
/** | |||
* Sets the generic signature of the class. | |||
* | |||
* <p>The generics of Java is implemented by the erasure technique. | |||
* After compilation, all type parameters are dropped off from the | |||
* main part of a class file. However, for reflection, the type | |||
* parameters must be encoded into generic signatures and attached | |||
* to a class file. | |||
* | |||
* <p>For example, | |||
* | |||
* <pre>class List<T> { | |||
* T value; | |||
* T get() { return value; } | |||
* void set(T v) { value = v; } | |||
* } | |||
* </pre> | |||
* | |||
* <p>this class is generated by the following code: | |||
* | |||
* <pre> | |||
* ClassPool pool = ClassPool.getDefault(); | |||
* CtClass cc = pool.makeClass("List"); | |||
* CtClass objectClass = pool.get(CtClass.javaLangObject); | |||
* ClassSignature cs = new ClassSignature( | |||
* new TypeParameter[] { new TypeParameter("T") }); | |||
* cc.setGenericSignature(cs.encode()); // <T:Ljava/lang/Object;>Ljava/lang/Object; | |||
* | |||
* CtField f = new CtField(objClass, "value", cc); | |||
* TypeVariable tvar = new TypeVariable("T"); | |||
* f.setGenericSignature(tvar.encode()); // TT; | |||
* cc.addField(f); | |||
* | |||
* CtMethod m = CtNewMethod.make("public Object get(){return value;}", cc); | |||
* MethodSignature ms = new MethodSignature(null, null, tvar, null); | |||
* m.setGenericSignature(ms.encode()); // ()TT; | |||
* cc.addMethod(m); | |||
* | |||
* CtMethod m2 = CtNewMethod.make("public void set(Object v){value = v;}", cc); | |||
* MethodSignature ms2 = new MethodSignature(null, new Type[] { tvar }, | |||
* new BaseType("void"), null); | |||
* m2.setGenericSignature(ms2.encode()); // (TT;)V; | |||
* cc.addMethod(m2); | |||
* | |||
* cc.writeFile(); | |||
* </pre> | |||
* | |||
* <p>The generated class file is equivalent to the following: | |||
* | |||
* <pre>class List { | |||
* Object value; | |||
* Object get() { return value; } | |||
* void set(Object v) { value = v; } | |||
* }</pre> | |||
* | |||
* <p>but it includes generic signatures for the class, the field, | |||
* and the methods so that the type variable <code>T</code> can be | |||
* accessible through reflection. | |||
* | |||
* @param sig a generic signature. | |||
* @see javassist.bytecode.SignatureAttribute.ClassSignature#encode() | |||
* @see javassist.bytecode.SignatureAttribute.MethodSignature#encode() | |||
* @see CtMember#setGenericSignature(String) | |||
* @since 3.17 | |||
*/ | |||
public void setGenericSignature(String sig) { checkModify(); } | |||
/** | |||
* Substitutes <code>newName</code> for all occurrences of a class | |||
* name <code>oldName</code> in the class file. |
@@ -47,6 +47,7 @@ import javassist.bytecode.FieldInfo; | |||
import javassist.bytecode.InnerClassesAttribute; | |||
import javassist.bytecode.MethodInfo; | |||
import javassist.bytecode.ParameterAnnotationsAttribute; | |||
import javassist.bytecode.SignatureAttribute; | |||
import javassist.bytecode.annotation.Annotation; | |||
import javassist.compiler.AccessorMaker; | |||
import javassist.compiler.CompileError; | |||
@@ -336,6 +337,18 @@ class CtClassType extends CtClass { | |||
classPool.classNameChanged(oldname, this); | |||
} | |||
public String getGenericSignature() { | |||
SignatureAttribute sa | |||
= (SignatureAttribute)getClassFile2().getAttribute(SignatureAttribute.tag); | |||
return sa == null ? null : sa.getSignature(); | |||
} | |||
public void setGenericSignature(String sig) { | |||
ClassFile cf = getClassFile(); | |||
SignatureAttribute sa = new SignatureAttribute(cf.getConstPool(), sig); | |||
cf.addAttribute(sa); | |||
} | |||
public void replaceClassName(ClassMap classnames) | |||
throws RuntimeException | |||
{ |
@@ -327,19 +327,43 @@ public class CtField extends CtMember { | |||
* | |||
* <p>Note that the returned string is not the type signature | |||
* contained in the <code>SignatureAttirbute</code>. It is | |||
* a descriptor. To obtain a type signature, call the following | |||
* methods: | |||
* | |||
* <ul><pre>getFieldInfo().getAttribute(SignatureAttribute.tag) | |||
* </pre></ul> | |||
* a descriptor. | |||
* | |||
* @see javassist.bytecode.Descriptor | |||
* @see javassist.bytecode.SignatureAttribute | |||
* @see #getGenericSignature() | |||
*/ | |||
public String getSignature() { | |||
return fieldInfo.getDescriptor(); | |||
} | |||
/** | |||
* Returns the generic signature of the field. | |||
* It represents a type including type variables. | |||
* | |||
* @see SignatureAttribute#toFieldSignature(String) | |||
* @since 3.17 | |||
*/ | |||
public String getGenericSignature() { | |||
SignatureAttribute sa | |||
= (SignatureAttribute)fieldInfo.getAttribute(SignatureAttribute.tag); | |||
return sa == null ? null : sa.getSignature(); | |||
} | |||
/** | |||
* Set the generic signature of the field. | |||
* It represents a type including type variables. | |||
* See {@link javassist.CtClass#setGenericSignature(String)} | |||
* for a code sample. | |||
* | |||
* @param sig a new generic signature. | |||
* @see javassist.bytecode.SignatureAttribute.ObjectType#encode() | |||
* @since 3.17 | |||
*/ | |||
public void setGenericSignature(String sig) { | |||
declaringClass.checkModify(); | |||
fieldInfo.addAttribute(new SignatureAttribute(fieldInfo.getConstPool(), sig)); | |||
} | |||
/** | |||
* Returns the type of the field. | |||
*/ |
@@ -42,6 +42,8 @@ public abstract class CtMember { | |||
public String getSignature() { return null; } | |||
public void setAttribute(String name, byte[] data) {} | |||
public void setModifiers(int mod) {} | |||
public String getGenericSignature() { return null; } | |||
public void setGenericSignature(String sig) {} | |||
private CtMember methodTail; | |||
private CtMember consTail; // constructor tail | |||
@@ -269,6 +271,27 @@ public abstract class CtMember { | |||
*/ | |||
public abstract String getSignature(); | |||
/** | |||
* Returns the generic signature of the member. | |||
* | |||
* @see javassist.bytecode.SignatureAttribute#toFieldSignature(String) | |||
* @see javassist.bytecode.SignatureAttribute#toMethodSignature(String) | |||
* @see CtClass#getGenericSignature() | |||
* @since 3.17 | |||
*/ | |||
public abstract String getGenericSignature(); | |||
/** | |||
* Sets the generic signature of the member. | |||
* | |||
* @param sig a new generic signature. | |||
* @see javassist.bytecode.SignatureAttribute.ObjectType#encode() | |||
* @see javassist.bytecode.SignatureAttribute.MethodSignature#encode() | |||
* @see CtClass#setGenericSignature(String) | |||
* @since 3.17 | |||
*/ | |||
public abstract void setGenericSignature(String sig); | |||
/** | |||
* Obtains a user-defined attribute with the given name. | |||
* If that attribute is not found in the class file, this |
@@ -38,7 +38,7 @@ public class SignatureAttribute extends AttributeInfo { | |||
} | |||
/** | |||
* Constructs a Signature attribute. | |||
* Constructs a <code>Signature</code> attribute. | |||
* | |||
* @param cp a constant pool table. | |||
* @param signature the signature represented by this attribute. | |||
@@ -53,17 +53,18 @@ public class SignatureAttribute extends AttributeInfo { | |||
} | |||
/** | |||
* Returns the signature indicated by <code>signature_index</code>. | |||
* Returns the generic signature indicated by <code>signature_index</code>. | |||
* | |||
* @see #toClassSignature(String) | |||
* @see #toMethodSignature(String) | |||
* @see #toFieldSignature(String) | |||
*/ | |||
public String getSignature() { | |||
return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0)); | |||
} | |||
/** | |||
* Sets <code>signature_index</code> to the index of the given signature, | |||
* Sets <code>signature_index</code> to the index of the given generic signature, | |||
* which is added to a constant pool. | |||
* | |||
* @param sig new signature. | |||
@@ -177,10 +178,27 @@ public class SignatureAttribute extends AttributeInfo { | |||
TypeParameter[] params; | |||
ClassType superClass; | |||
ClassType[] interfaces; | |||
ClassSignature(TypeParameter[] p, ClassType s, ClassType[] i) { | |||
params = p; | |||
superClass = s; | |||
interfaces = i; | |||
/** | |||
* Constructs a class signature. | |||
* | |||
* @param p type parameters. | |||
* @param s the super class. | |||
* @param i the interface types. | |||
*/ | |||
public ClassSignature(TypeParameter[] p, ClassType s, ClassType[] i) { | |||
params = p == null ? new TypeParameter[0] : p; | |||
superClass = s == null ? ClassType.OBJECT : s; | |||
interfaces = i == null ? new ClassType[0] : i; | |||
} | |||
/** | |||
* Constructs a class signature. | |||
* | |||
* @param p type parameters. | |||
*/ | |||
public ClassSignature(TypeParameter[] p) { | |||
this(p, null, null); | |||
} | |||
/** | |||
@@ -219,6 +237,26 @@ public class SignatureAttribute extends AttributeInfo { | |||
return sbuf.toString(); | |||
} | |||
/** | |||
* Returns the encoded string representing the method type signature. | |||
*/ | |||
public String encode() { | |||
StringBuffer sbuf = new StringBuffer(); | |||
if (params.length > 0) { | |||
sbuf.append('<'); | |||
for (int i = 0; i < params.length; i++) | |||
params[i].encode(sbuf); | |||
sbuf.append('>'); | |||
} | |||
superClass.encode(sbuf); | |||
for (int i = 0; i < interfaces.length; i++) | |||
interfaces[i].encode(sbuf); | |||
return sbuf.toString(); | |||
} | |||
} | |||
/** | |||
@@ -230,11 +268,20 @@ public class SignatureAttribute extends AttributeInfo { | |||
Type retType; | |||
ObjectType[] exceptions; | |||
MethodSignature(TypeParameter[] tp, Type[] p, Type ret, ObjectType[] ex) { | |||
typeParams = tp; | |||
params = p; | |||
retType = ret; | |||
exceptions = ex; | |||
/** | |||
* Constructs a method type signature. Any parameter can be null | |||
* to represent <code>void</code> or nothing. | |||
* | |||
* @param tp type parameters. | |||
* @param p parameter types. | |||
* @param ret a return type. | |||
* @param ex exception types. | |||
*/ | |||
public MethodSignature(TypeParameter[] tp, Type[] p, Type ret, ObjectType[] ex) { | |||
typeParams = tp == null ? new TypeParameter[0] : tp; | |||
params = p == null ? new Type[0] : p; | |||
retType = ret == null ? new BaseType("void") : ret; | |||
exceptions = ex == null ? new ObjectType[0] : ex; | |||
} | |||
/** | |||
@@ -282,10 +329,40 @@ public class SignatureAttribute extends AttributeInfo { | |||
return sbuf.toString(); | |||
} | |||
/** | |||
* Returns the encoded string representing the method type signature. | |||
*/ | |||
public String encode() { | |||
StringBuffer sbuf = new StringBuffer(); | |||
if (typeParams.length > 0) { | |||
sbuf.append('<'); | |||
for (int i = 0; i < typeParams.length; i++) | |||
typeParams[i].encode(sbuf); | |||
sbuf.append('>'); | |||
} | |||
sbuf.append('('); | |||
for (int i = 0; i < params.length; i++) | |||
params[i].encode(sbuf); | |||
sbuf.append(')'); | |||
retType.encode(sbuf); | |||
if (exceptions.length > 0) | |||
for (int i = 0; i < exceptions.length; i++) { | |||
sbuf.append('^'); | |||
exceptions[i].encode(sbuf); | |||
} | |||
return sbuf.toString(); | |||
} | |||
} | |||
/** | |||
* Formal type parameters. | |||
* | |||
* @see TypeArgument | |||
*/ | |||
public static class TypeParameter { | |||
String name; | |||
@@ -298,6 +375,33 @@ public class SignatureAttribute extends AttributeInfo { | |||
superInterfaces = si; | |||
} | |||
/** | |||
* Constructs a <code>TypeParameter</code> representing a type parametre | |||
* like <code><T extends ... ><code>. | |||
* | |||
* @param name parameter name. | |||
* @param superClass an upper bound class-type (or null). | |||
* @param superInterfaces an upper bound interface-type (or null). | |||
*/ | |||
public TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces) { | |||
this.name = name; | |||
this.superClass = superClass; | |||
if (superInterfaces == null) | |||
this.superInterfaces = new ObjectType[0]; | |||
else | |||
this.superInterfaces = superInterfaces; | |||
} | |||
/** | |||
* Constructs a <code>TypeParameter</code> representing a type parameter | |||
* like <code><T><code>. | |||
* | |||
* @param name parameter name. | |||
*/ | |||
public TypeParameter(String name) { | |||
this(name, null, null); | |||
} | |||
/** | |||
* Returns the name of the type parameter. | |||
*/ | |||
@@ -307,8 +411,6 @@ public class SignatureAttribute extends AttributeInfo { | |||
/** | |||
* Returns the class bound of this parameter. | |||
* | |||
* @return null if the class bound is not specified. | |||
*/ | |||
public ObjectType getClassBound() { return superClass; } | |||
@@ -353,10 +455,27 @@ public class SignatureAttribute extends AttributeInfo { | |||
sbuf.append('>'); | |||
} | |||
void encode(StringBuffer sb) { | |||
sb.append(name); | |||
if (superClass == null) | |||
sb.append(":Ljava/lang/Object;"); | |||
else { | |||
sb.append(':'); | |||
superClass.encode(sb); | |||
} | |||
for (int i = 0; i < superInterfaces.length; i++) { | |||
sb.append(':'); | |||
superInterfaces[i].encode(sb); | |||
} | |||
} | |||
} | |||
/** | |||
* Type argument. | |||
* | |||
* @see TypeParameter | |||
*/ | |||
public static class TypeArgument { | |||
ObjectType arg; | |||
@@ -367,6 +486,44 @@ public class SignatureAttribute extends AttributeInfo { | |||
wildcard = w; | |||
} | |||
/** | |||
* Constructs a <code>TypeArgument</code>. | |||
* A type argument is <code><String></code>, <code><int[]></code>, | |||
* or a type variable <code><T></code>, etc. | |||
* | |||
* @param t a class type, an array type, or a type variable. | |||
*/ | |||
public TypeArgument(ObjectType t) { | |||
this(t, ' '); | |||
} | |||
/** | |||
* Constructs a <code>TypeArgument</code> representing <code><?></code>. | |||
*/ | |||
public TypeArgument() { | |||
this(null, '*'); | |||
} | |||
/** | |||
* A factory method constructing a <code>TypeArgument</code> with an upper bound. | |||
* It represents <code><? extends ... ></code> | |||
* | |||
* @param t an upper bound type. | |||
*/ | |||
public static TypeArgument subclassOf(ObjectType t) { | |||
return new TypeArgument(t, '+'); | |||
} | |||
/** | |||
* A factory method constructing a <code>TypeArgument</code> with an lower bound. | |||
* It represents <code><? super ... ></code> | |||
* | |||
* @param t an lower bbound type. | |||
*/ | |||
public static TypeArgument superOf(ObjectType t) { | |||
return new TypeArgument(t, '-'); | |||
} | |||
/** | |||
* Returns the kind of this type argument. | |||
* | |||
@@ -405,12 +562,27 @@ public class SignatureAttribute extends AttributeInfo { | |||
else | |||
return "? super " + type; | |||
} | |||
static void encode(StringBuffer sb, TypeArgument[] args) { | |||
sb.append('<'); | |||
for (int i = 0; i < args.length; i++) { | |||
TypeArgument ta = args[i]; | |||
if (ta.isWildcard()) | |||
sb.append(ta.wildcard); | |||
if (ta.getType() != null) | |||
ta.getType().encode(sb); | |||
} | |||
sb.append('>'); | |||
} | |||
} | |||
/** | |||
* Primitive types and object types. | |||
*/ | |||
public static abstract class Type { | |||
abstract void encode(StringBuffer sb); | |||
static void toString(StringBuffer sbuf, Type[] ts) { | |||
for (int i = 0; i < ts.length; i++) { | |||
if (i > 0) | |||
@@ -428,6 +600,15 @@ public class SignatureAttribute extends AttributeInfo { | |||
char descriptor; | |||
BaseType(char c) { descriptor = c; } | |||
/** | |||
* Constructs a <code>BaseType</code>. | |||
* | |||
* @param typeName <code>void</code>, <code>int</code>, ... | |||
*/ | |||
public BaseType(String typeName) { | |||
this(Descriptor.of(typeName).charAt(0)); | |||
} | |||
/** | |||
* Returns the descriptor representing this primitive type. | |||
* | |||
@@ -449,12 +630,26 @@ public class SignatureAttribute extends AttributeInfo { | |||
public String toString() { | |||
return Descriptor.toClassName(Character.toString(descriptor)); | |||
} | |||
void encode(StringBuffer sb) { | |||
sb.append(descriptor); | |||
} | |||
} | |||
/** | |||
* Class types, array types, and type variables. | |||
* This class is also used for representing a field type. | |||
*/ | |||
public static abstract class ObjectType extends Type {} | |||
public static abstract class ObjectType extends Type { | |||
/** | |||
* Returns the encoded string representing the object type signature. | |||
*/ | |||
public String encode() { | |||
StringBuffer sb = new StringBuffer(); | |||
encode(sb); | |||
return sb.toString(); | |||
} | |||
} | |||
/** | |||
* Class types. | |||
@@ -476,6 +671,23 @@ public class SignatureAttribute extends AttributeInfo { | |||
arguments = targs; | |||
} | |||
/** | |||
* A class type representing <code>java.lang.Object</code>. | |||
*/ | |||
public static ClassType OBJECT = new ClassType("java.lang.Object", null); | |||
/** | |||
* Constructs a <code>ClassType</code>. It represents | |||
* the name of a non-nested class. | |||
* | |||
* @param className a fully qualified class name. | |||
* @param args type arguments or null. | |||
*/ | |||
public ClassType(String className, TypeArgument[] args) { | |||
name = className; | |||
arguments = args; | |||
} | |||
/** | |||
* Returns the class name. | |||
*/ | |||
@@ -523,6 +735,24 @@ public class SignatureAttribute extends AttributeInfo { | |||
return sbuf.toString(); | |||
} | |||
void encode(StringBuffer sb) { | |||
sb.append('L'); | |||
encode2(sb); | |||
sb.append(';'); | |||
} | |||
void encode2(StringBuffer sb) { | |||
ClassType parent = getDeclaringClass(); | |||
if (parent != null) { | |||
parent.encode2(sb); | |||
sb.append('$'); | |||
} | |||
sb.append(name.replace('.', '/')); | |||
if (arguments != null) | |||
TypeArgument.encode(sb, arguments); | |||
} | |||
} | |||
/** | |||
@@ -536,6 +766,19 @@ public class SignatureAttribute extends AttributeInfo { | |||
parent = p; | |||
} | |||
/** | |||
* Constructs a <code>NestedClassType</code>. | |||
* | |||
* @param parent the class surrounding this class type. | |||
* @param className a simple class name. It does not include | |||
* a package name or a parent's class name. | |||
* @param args type parameters or null. | |||
*/ | |||
public NestedClassType(ClassType parent, String className, TypeArgument[] args) { | |||
super(className, args); | |||
this.parent = parent; | |||
} | |||
/** | |||
* Returns the class that declares this nested class. | |||
* This nested class is a member of that declaring class. | |||
@@ -550,6 +793,12 @@ public class SignatureAttribute extends AttributeInfo { | |||
int dim; | |||
Type componentType; | |||
/** | |||
* Constructs an <code>ArrayType</code>. | |||
* | |||
* @param d dimension. | |||
* @param comp the component type. | |||
*/ | |||
public ArrayType(int d, Type comp) { | |||
dim = d; | |||
componentType = comp; | |||
@@ -577,6 +826,13 @@ public class SignatureAttribute extends AttributeInfo { | |||
return sbuf.toString(); | |||
} | |||
void encode(StringBuffer sb) { | |||
for (int i = 0; i < dim; i++) | |||
sb.append('['); | |||
componentType.encode(sb); | |||
} | |||
} | |||
/** | |||
@@ -589,6 +845,15 @@ public class SignatureAttribute extends AttributeInfo { | |||
name = sig.substring(begin, end); | |||
} | |||
/** | |||
* Constructs a <code>TypeVariable</code>. | |||
* | |||
* @param name the name of a type variable. | |||
*/ | |||
public TypeVariable(String name) { | |||
this.name = name; | |||
} | |||
/** | |||
* Returns the variable name. | |||
*/ | |||
@@ -602,13 +867,21 @@ public class SignatureAttribute extends AttributeInfo { | |||
public String toString() { | |||
return name; | |||
} | |||
void encode(StringBuffer sb) { | |||
sb.append('T').append(name).append(';'); | |||
} | |||
} | |||
/** | |||
* Parses the given signature string as a class signature. | |||
* | |||
* @param sig the signature. | |||
* @param sig the signature obtained from the <code>SignatureAttribute</code> | |||
* of a <code>ClassFile</code>. | |||
* @return a tree-like data structure representing a class signature. It provides | |||
* convenient accessor methods. | |||
* @throws BadBytecode thrown when a syntactical error is found. | |||
* @see #getSignature() | |||
* @since 3.5 | |||
*/ | |||
public static ClassSignature toClassSignature(String sig) throws BadBytecode { | |||
@@ -623,8 +896,12 @@ public class SignatureAttribute extends AttributeInfo { | |||
/** | |||
* Parses the given signature string as a method type signature. | |||
* | |||
* @param sig the signature. | |||
* @param sig the signature obtained from the <code>SignatureAttribute</code> | |||
* of a <code>MethodInfo</code>. | |||
* @return @return a tree-like data structure representing a method signature. It provides | |||
* convenient accessor methods. | |||
* @throws BadBytecode thrown when a syntactical error is found. | |||
* @see #getSignature() | |||
* @since 3.5 | |||
*/ | |||
public static MethodSignature toMethodSignature(String sig) throws BadBytecode { | |||
@@ -639,9 +916,11 @@ public class SignatureAttribute extends AttributeInfo { | |||
/** | |||
* Parses the given signature string as a field type signature. | |||
* | |||
* @param sig the signature string. | |||
* @param sig the signature string obtained from the <code>SignatureAttribute</code> | |||
* of a <code>FieldInfo</code>. | |||
* @return the field type signature. | |||
* @throws BadBytecode thrown when a syntactical error is found. | |||
* @see #getSignature() | |||
* @since 3.5 | |||
*/ | |||
public static ObjectType toFieldSignature(String sig) throws BadBytecode { |
@@ -724,4 +724,42 @@ public class JvstTest4 extends JvstTestRoot { | |||
Object obj = make(cc.getName()); | |||
assertEquals(1, invoke(obj, "run")); | |||
} | |||
public void testGenericSignature() throws Exception { | |||
CtClass cc = sloader.makeClass("test4.GenSig"); | |||
CtClass objClass = sloader.get(CtClass.javaLangObject); | |||
SignatureAttribute.ClassSignature cs | |||
= new SignatureAttribute.ClassSignature( | |||
new SignatureAttribute.TypeParameter[] { | |||
new SignatureAttribute.TypeParameter("T") }); | |||
cc.setGenericSignature(cs.encode()); // <T:Ljava/lang/Object;>Ljava/lang/Object; | |||
CtField f = new CtField(objClass, "value", cc); | |||
SignatureAttribute.TypeVariable tvar = new SignatureAttribute.TypeVariable("T"); | |||
f.setGenericSignature(tvar.encode()); // TT; | |||
cc.addField(f); | |||
CtMethod m = CtNewMethod.make("public Object get(){return value;}", cc); | |||
SignatureAttribute.MethodSignature ms | |||
= new SignatureAttribute.MethodSignature(null, null, tvar, null); | |||
m.setGenericSignature(ms.encode()); // ()TT; | |||
cc.addMethod(m); | |||
CtMethod m2 = CtNewMethod.make("public void set(Object v){value = v;}", cc); | |||
SignatureAttribute.MethodSignature ms2 | |||
= new SignatureAttribute.MethodSignature(null, new SignatureAttribute.Type[] { tvar }, | |||
new SignatureAttribute.BaseType("void"), null); | |||
m2.setGenericSignature(ms2.encode()); // (TT;)V; | |||
cc.addMethod(m2); | |||
cc.writeFile(); | |||
Object obj = make(cc.getName()); | |||
Class clazz = obj.getClass(); | |||
assertEquals("T", clazz.getTypeParameters()[0].getName()); | |||
assertEquals("T", ((java.lang.reflect.TypeVariable)clazz.getDeclaredField("value").getGenericType()).getName()); | |||
java.lang.reflect.Method rm = clazz.getDeclaredMethod("get", new Class[0]); | |||
assertEquals("T", ((java.lang.reflect.TypeVariable)rm.getGenericReturnType()).getName()); | |||
java.lang.reflect.Method rm2 = clazz.getDeclaredMethod("set", new Class[] { Object.class }); | |||
assertEquals("T", ((java.lang.reflect.TypeVariable)rm2.getGenericParameterTypes()[0]).getName()); | |||
} | |||
} |
@@ -26,7 +26,8 @@ Shigeru Chiba | |||
<br>6. <a href="tutorial3.html#generics">Generics</a> | |||
<br>7. <a href="tutorial3.html#varargs">Varargs</a> | |||
<br>8. <a href="tutorial3.html#j2me">J2ME</a> | |||
<br>9. <a href="tutorial3.html#debug">Debug</a> | |||
<br>9. <a href="tutorial3.html#boxing">Boxing/Unboxing</a> | |||
<br>10. <a href="tutorial3.html#debug">Debug</a> | |||
</ul> | |||
<p><br> |
@@ -28,7 +28,9 @@ | |||
<p><a href="#j2me">8. J2ME</a> | |||
<p><a href="#debug">9. Debug</a> | |||
<p><a href="#boxing">9. Boxing/Unboxing | |||
<p><a href="#debug">10. Debug</a> | |||
<p><br> | |||
@@ -296,6 +298,11 @@ public Object get() { return value; } | |||
<p>Note that no type parameters are necessary. | |||
<p>However, if you need to make type parameters accessible through reflection | |||
during runtime, you have to add generic signatures to the class file. | |||
For more details, see the API documentation (javadoc) of the | |||
<code>setGenericSignature</code> method in the <code>CtClass</code>. | |||
<p><br> | |||
<h2><a name="varargs">7. Varargs</a></h2> | |||
@@ -359,7 +366,26 @@ objects, call the <code>getDeclaredMethods</code> method on a <code>CtClass</cod | |||
<p><br> | |||
<h2><a name="debug">9. Debug</h2> | |||
<h2><a name="boxing">9. Boxing/Unboxing</h2> | |||
<p>Boxing and unboxing in Java are syntactic sugar. There is no bytecode for | |||
boxing or unboxing. So the compiler of Javassist does not support them. | |||
For example, the following statement is valid in Java: | |||
<ul><pre> | |||
Integer i = 3; | |||
</pre></ul> | |||
<p>since boxing is implicitly performed. For Javassist, however, you must explicitly | |||
convert a value type from <code>int</code> to <code>Integer</code>: | |||
<ul><pre> | |||
Integer i = new Integer(3); | |||
</pre></ul> | |||
<p><br> | |||
<h2><a name="debug">10. Debug</h2> | |||
<p>Set <code>CtClass.debugDump</code> to a directory name. | |||
Then all class files modified and generated by Javassist are saved in that |