From e2cfbeaed7be298c93251f6f9af480cdba84f68f Mon Sep 17 00:00:00 2001 From: chiba Date: Sun, 17 Jun 2012 15:01:27 +0000 Subject: [PATCH] implemented JASSIST-170 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@639 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- Readme.html | 2 +- src/main/javassist/CtBehavior.java | 36 +- src/main/javassist/CtClass.java | 84 +++++ src/main/javassist/CtClassType.java | 13 + src/main/javassist/CtField.java | 36 +- src/main/javassist/CtMember.java | 23 ++ .../bytecode/SignatureAttribute.java | 315 +++++++++++++++++- src/test/javassist/JvstTest4.java | 38 +++ tutorial/tutorial.html | 3 +- tutorial/tutorial3.html | 30 +- 10 files changed, 546 insertions(+), 34 deletions(-) diff --git a/Readme.html b/Readme.html index ef74f171..0d292238 100644 --- a/Readme.html +++ b/Readme.html @@ -284,7 +284,7 @@ see javassist.Dump.

-version 3.17

-version 3.16.1 on March 6, 2012 diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index e01f868c..06873e2c 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -314,19 +314,43 @@ public abstract class CtBehavior extends CtMember { * *

Note that the returned string is not the type signature * contained in the SignatureAttirbute. It is - * a descriptor. To obtain a type signature, call the following - * methods: - * - *

+ * 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. * diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index 7f115d0d..bcf61e41 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -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. + * + *

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. + * + *

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. + * + *

For example, + * + *

class List {
+     *     T value;
+     *     T get() { return value; }
+     *     void set(T v) { value = v; }
+     * }
+     * 
+ * + *

this class is generated by the following code: + * + *

+     * 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();
+     * 
+ * + *

The generated class file is equivalent to the following: + * + *

class List {
+     *     Object value;
+     *     Object get() { return value; }
+     *     void set(Object v) { value = v; }
+     * }
+ * + *

but it includes generic signatures for the class, the field, + * and the methods so that the type variable T 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 newName for all occurrences of a class * name oldName in the class file. diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java index abbc25fa..4d10b5dd 100644 --- a/src/main/javassist/CtClassType.java +++ b/src/main/javassist/CtClassType.java @@ -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 { diff --git a/src/main/javassist/CtField.java b/src/main/javassist/CtField.java index a16e1396..16e450bf 100644 --- a/src/main/javassist/CtField.java +++ b/src/main/javassist/CtField.java @@ -327,19 +327,43 @@ public class CtField extends CtMember { * *

Note that the returned string is not the type signature * contained in the SignatureAttirbute. It is - * a descriptor. To obtain a type signature, call the following - * methods: - * - *

+ * 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. */ diff --git a/src/main/javassist/CtMember.java b/src/main/javassist/CtMember.java index e75130d5..ae141c65 100644 --- a/src/main/javassist/CtMember.java +++ b/src/main/javassist/CtMember.java @@ -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 diff --git a/src/main/javassist/bytecode/SignatureAttribute.java b/src/main/javassist/bytecode/SignatureAttribute.java index 08d7f3b8..9e6921c5 100644 --- a/src/main/javassist/bytecode/SignatureAttribute.java +++ b/src/main/javassist/bytecode/SignatureAttribute.java @@ -38,7 +38,7 @@ public class SignatureAttribute extends AttributeInfo { } /** - * Constructs a Signature attribute. + * Constructs a Signature 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 signature_index. + * Returns the generic signature indicated by signature_index. * * @see #toClassSignature(String) * @see #toMethodSignature(String) + * @see #toFieldSignature(String) */ public String getSignature() { return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0)); } /** - * Sets signature_index to the index of the given signature, + * Sets signature_index 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 void 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 TypeParameter representing a type parametre + * like <T extends ... >. + * + * @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 TypeParameter representing a type parameter + * like <T>. + * + * @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 TypeArgument. + * A type argument is <String>, <int[]>, + * or a type variable <T>, etc. + * + * @param t a class type, an array type, or a type variable. + */ + public TypeArgument(ObjectType t) { + this(t, ' '); + } + + /** + * Constructs a TypeArgument representing <?>. + */ + public TypeArgument() { + this(null, '*'); + } + + /** + * A factory method constructing a TypeArgument with an upper bound. + * It represents <? extends ... > + * + * @param t an upper bound type. + */ + public static TypeArgument subclassOf(ObjectType t) { + return new TypeArgument(t, '+'); + } + + /** + * A factory method constructing a TypeArgument with an lower bound. + * It represents <? super ... > + * + * @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 BaseType. + * + * @param typeName void, int, ... + */ + 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 java.lang.Object. + */ + public static ClassType OBJECT = new ClassType("java.lang.Object", null); + + /** + * Constructs a ClassType. 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 NestedClassType. + * + * @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 ArrayType. + * + * @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 TypeVariable. + * + * @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 SignatureAttribute + * of a ClassFile. + * @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 SignatureAttribute + * of a MethodInfo. + * @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 SignatureAttribute + * of a FieldInfo. * @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 { diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java index f7319008..2a732cf4 100644 --- a/src/test/javassist/JvstTest4.java +++ b/src/test/javassist/JvstTest4.java @@ -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()); // 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()); + } } diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html index 44bfd9eb..f7bb622a 100644 --- a/tutorial/tutorial.html +++ b/tutorial/tutorial.html @@ -26,7 +26,8 @@ Shigeru Chiba
6. Generics
7. Varargs
8. J2ME -
9. Debug +
9. Boxing/Unboxing +
10. Debug


diff --git a/tutorial/tutorial3.html b/tutorial/tutorial3.html index e07372bd..7c505e0b 100644 --- a/tutorial/tutorial3.html +++ b/tutorial/tutorial3.html @@ -28,7 +28,9 @@

8. J2ME -

9. Debug +

9. Boxing/Unboxing + +

10. Debug


@@ -296,6 +298,11 @@ public Object get() { return value; }

Note that no type parameters are necessary. +

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 +setGenericSignature method in the CtClass. +


7. Varargs

@@ -359,7 +366,26 @@ objects, call the getDeclaredMethods method on a CtClass
-

9. Debug

+

9. Boxing/Unboxing

+ +

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: + +

    +Integer i = 3;
    +
+ +

since boxing is implicitly performed. For Javassist, however, you must explicitly +convert a value type from int to Integer: + +

    +Integer i = new Integer(3);
    +
+ +


+ +

10. Debug

Set CtClass.debugDump to a directory name. Then all class files modified and generated by Javassist are saved in that -- 2.39.5