diff options
author | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2005-10-27 11:04:32 +0000 |
---|---|---|
committer | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2005-10-27 11:04:32 +0000 |
commit | 6aaacd96767eae3bf716a542ac67bcff7336380d (patch) | |
tree | 0d25da25d8702b5ddbe60aad26fa05a3c70e8d46 | |
parent | 0446eb7e747fd18bfed7eaf0ab0fe3a7c96aadc7 (diff) | |
download | javassist-6aaacd96767eae3bf716a542ac67bcff7336380d.tar.gz javassist-6aaacd96767eae3bf716a542ac67bcff7336380d.zip |
Implemented CtConstructor#toMethod().
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@212 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
-rw-r--r-- | src/main/javassist/CtBehavior.java | 39 | ||||
-rw-r--r-- | src/main/javassist/CtConstructor.java | 99 | ||||
-rw-r--r-- | src/main/javassist/CtMethod.java | 40 | ||||
-rw-r--r-- | src/main/javassist/bytecode/CodeIterator.java | 18 | ||||
-rw-r--r-- | src/main/javassist/bytecode/Descriptor.java | 81 | ||||
-rw-r--r-- | tutorial/tutorial.html | 17 |
6 files changed, 230 insertions, 64 deletions
diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index 3f271217..c556910b 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -34,6 +34,45 @@ public abstract class CtBehavior extends CtMember { methodInfo = minfo; } + /** + * @param isCons true if this is a constructor. + */ + void copy(CtBehavior src, boolean isCons, ClassMap map) + throws CannotCompileException + { + CtClass declaring = declaringClass; + MethodInfo srcInfo = src.methodInfo; + CtClass srcClass = src.getDeclaringClass(); + ConstPool cp = declaring.getClassFile2().getConstPool(); + if (map == null) + map = new ClassMap(); + + map.put(srcClass.getName(), declaring.getName()); + try { + boolean patch = false; + CtClass srcSuper = srcClass.getSuperclass(); + String destSuperName = declaring.getSuperclass().getName(); + if (srcSuper != null) { + String srcSuperName = srcSuper.getName(); + if (!srcSuperName.equals(destSuperName)) + if (srcSuperName.equals(CtClass.javaLangObject)) + patch = true; + else + map.put(srcSuperName, destSuperName); + } + + methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map); + if (isCons && patch) + methodInfo.setSuperclass(destSuperName); + } + catch (NotFoundException e) { + throw new CannotCompileException(e); + } + catch (BadBytecode e) { + throw new CannotCompileException(e); + } + } + protected void extendToString(StringBuffer buffer) { buffer.append(' '); buffer.append(getName()); diff --git a/src/main/javassist/CtConstructor.java b/src/main/javassist/CtConstructor.java index 46fc334a..7bcf2622 100644 --- a/src/main/javassist/CtConstructor.java +++ b/src/main/javassist/CtConstructor.java @@ -98,36 +98,7 @@ public final class CtConstructor extends CtBehavior { throws CannotCompileException { this((MethodInfo)null, declaring); - MethodInfo srcInfo = src.methodInfo; - CtClass srcClass = src.getDeclaringClass(); - ConstPool cp = declaring.getClassFile2().getConstPool(); - if (map == null) - map = new ClassMap(); - - map.put(srcClass.getName(), declaring.getName()); - try { - boolean patch = false; - CtClass srcSuper = srcClass.getSuperclass(); - String destSuperName = declaring.getSuperclass().getName(); - if (srcSuper != null) { - String srcSuperName = srcSuper.getName(); - if (!srcSuperName.equals(destSuperName)) - if (srcSuperName.equals(CtClass.javaLangObject)) - patch = true; - else - map.put(srcSuperName, destSuperName); - } - - methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map); - if (patch) - methodInfo.setSuperclass(destSuperName); - } - catch (NotFoundException e) { - throw new CannotCompileException(e); - } - catch (BadBytecode e) { - throw new CannotCompileException(e); - } + copy(src, true, map); } /** @@ -272,4 +243,72 @@ public final class CtConstructor extends CtBehavior { throw new CannotCompileException(e); } } + + /** + * Makes a copy of this constructor and converts it into a method. + * The signature of the mehtod is the same as the that of this constructor. + * The return type is <code>void</code>. The resulting method must be + * appended to the class specified by <code>declaring</code>. + * If this constructor is a static initializer, the resulting method takes + * no parameter. + * + * <p>An occurrence of another constructor call <code>this()</code> + * or a super constructor call <code>super()</code> is + * eliminated from the resulting method. + * + * <p>The immediate super class of the class declaring this constructor + * must be also a super class of the class declaring the resulting method. + * If the constructor accesses a field, the class declaring the resulting method + * must also declare a field with the same name and type. + * + * @param name the name of the resulting method. + * @param declaring the class declaring the resulting method. + */ + public CtMethod toMethod(String name, CtClass declaring) + throws CannotCompileException + { + CtMethod method = new CtMethod(null, declaring); + method.copy(this, false, null); + if (isConstructor()) { + MethodInfo minfo = method.getMethodInfo2(); + CodeAttribute ca = minfo.getCodeAttribute(); + if (ca != null) + removeConsCall(ca); + } + + method.setName(name); + return method; + } + + private static void removeConsCall(CodeAttribute ca) + throws CannotCompileException + { + CodeIterator iterator = ca.iterator(); + try { + int pos = iterator.skipConstructor(); + if (pos >= 0) { + int mref = iterator.u16bitAt(pos + 1); + String desc = ca.getConstPool().getMethodrefType(mref); + int num = Descriptor.numOfParameters(desc) + 1; + if (num > 3) + iterator.insertGap(pos, num - 3); + + iterator.writeByte(Opcode.POP, pos++); // this + iterator.writeByte(Opcode.NOP, pos); + iterator.writeByte(Opcode.NOP, pos + 1); + Descriptor.Iterator it = new Descriptor.Iterator(desc); + while (true) { + it.next(); + if (it.isParameter()) + iterator.writeByte(it.is2byte() ? Opcode.POP2 : Opcode.POP, + pos++); + else + break; + } + } + } + catch (BadBytecode e) { + throw new CannotCompileException(e); + } + } } diff --git a/src/main/javassist/CtMethod.java b/src/main/javassist/CtMethod.java index 9c1532d0..043c8d3b 100644 --- a/src/main/javassist/CtMethod.java +++ b/src/main/javassist/CtMethod.java @@ -22,6 +22,7 @@ import javassist.bytecode.*; * * <p>See the super class <code>CtBehavior</code> since * a number of useful methods are in <code>CtBehavior</code>. + * A number of useful factory methods are in <code>CtNewMethod</code>. * * @see CtClass#getDeclaredMethods() * @see CtNewMethod @@ -106,30 +107,23 @@ public final class CtMethod extends CtBehavior { throws CannotCompileException { this(null, declaring); - MethodInfo srcInfo = src.methodInfo; - CtClass srcClass = src.getDeclaringClass(); - ConstPool cp = declaring.getClassFile2().getConstPool(); - if (map == null) - map = new ClassMap(); + copy(src, false, map); + } - map.put(srcClass.getName(), declaring.getName()); - try { - CtClass srcSuper = srcClass.getSuperclass(); - if (srcSuper != null) { - String srcSuperName = srcSuper.getName(); - if (!srcSuperName.equals(CtClass.javaLangObject)) - map.put(srcSuperName, - declaring.getSuperclass().getName()); - } - - methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map); - } - catch (NotFoundException e) { - throw new CannotCompileException(e); - } - catch (BadBytecode e) { - throw new CannotCompileException(e); - } + /** + * Compiles the given source code and creates a method. + * This method simply delegates to <code>make()</code> in + * <code>CtNewMethod</code>. See it for more details. + * <code>CtNewMethod</code> has a number of useful factory methods. + * + * @param src the source text. + * @param declaring the class to which the created method is added. + * @see CtNewMethod.make(String, CtClass) + */ + public static CtMethod make(String src, CtClass declaring) + throws CannotCompileException + { + return CtNewMethod.make(src, declaring); } /** diff --git a/src/main/javassist/bytecode/CodeIterator.java b/src/main/javassist/bytecode/CodeIterator.java index 531dfaa1..ab9ce7d9 100644 --- a/src/main/javassist/bytecode/CodeIterator.java +++ b/src/main/javassist/bytecode/CodeIterator.java @@ -154,11 +154,11 @@ public class CodeIterator implements Opcode { } /** - * Moves to the first instruction following - * constructor invocation <code>super()</code> or <code>this()</code>. + * Moves to the instruction for + * either <code>super()</code> or <code>this()</code>. * - * <p>This method skips all the instructions for executing - * <code>super()</code> or <code>this()</code>, which should be + * <p>This method skips all the instructions for computing arguments + * to <code>super()</code> or <code>this()</code>, which should be * placed at the beginning of a constructor body. * * <p>This method returns the index of INVOKESPECIAL instruction @@ -176,10 +176,9 @@ public class CodeIterator implements Opcode { } /** - * Moves to the first instruction following super - * constructor invocation <code>super()</code>. + * Moves to the instruction for <code>super()</code>. * - * <p>This method skips all the instructions for executing + * <p>This method skips all the instructions for computing arguments to * <code>super()</code>, which should be * placed at the beginning of a constructor body. * @@ -199,10 +198,9 @@ public class CodeIterator implements Opcode { } /** - * Moves to the first instruction following explicit - * constructor invocation <code>this()</code>. + * Moves to the instruction for <code>this()</code>. * - * <p>This method skips all the instructions for executing + * <p>This method skips all the instructions for computing arguments to * <code>this()</code>, which should be * placed at the beginning of a constructor body. * diff --git a/src/main/javassist/bytecode/Descriptor.java b/src/main/javassist/bytecode/Descriptor.java index a09f198b..b67e7a49 100644 --- a/src/main/javassist/bytecode/Descriptor.java +++ b/src/main/javassist/bytecode/Descriptor.java @@ -665,4 +665,85 @@ public class Descriptor { return n; } + + /** + * An Iterator over a descriptor. + */ + public static class Iterator { + private String desc; + private int index, curPos; + private boolean param; + + /** + * Constructs an iterator. + * + * @param s descriptor. + */ + public Iterator(String s) { + desc = s; + index = curPos = 0; + param = false; + } + + /** + * Returns true if the iteration has more elements. + */ + public boolean hasNext() { + return index < desc.length(); + } + + /** + * Returns true if the current element is a parameter type. + */ + public boolean isParameter() { return param; } + + /** + * Returns the first character of the current element. + * @return + */ + public char currentChar() { return desc.charAt(curPos); } + + /** + * Returns true if the current element is double or long type. + */ + public boolean is2byte() { + char c = currentChar(); + return c == 'D' || c == 'J'; + } + + /** + * Returns the position of the next type character. + * That type character becomes a new current element. + */ + public int next() { + int nextPos = index; + char c = desc.charAt(nextPos); + if (c == '(') { + ++index; + c = desc.charAt(++nextPos); + param = true; + } + + if (c == ')') { + ++index; + c = desc.charAt(++nextPos); + param = false; + } + + while (c == '[') + c = desc.charAt(++nextPos); + + if (c == 'L') { + nextPos = desc.indexOf(';', nextPos) + 1; + if (nextPos <= 0) + throw new IndexOutOfBoundsException("bad descriptor"); + } + else + ++nextPos; + + curPos = index; + index = nextPos; + return curPos; + } + } } diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html index 29c56a68..c2d54a87 100644 --- a/tutorial/tutorial.html +++ b/tutorial/tutorial.html @@ -63,6 +63,8 @@ In the case of the program shown above, the <code>test.Rectangle</code> is obtained from the <code>ClassPool</code> object and it is assigned to a variable <code>cc</code>. +The <code>ClassPool</code> object returned by <code>getDfault()</code> +searches the default system search path. <p>From the implementation viewpoint, <code>ClassPool</code> is a hash table of <code>CtClass</code> objects, which uses the class names as @@ -90,6 +92,17 @@ modified bytecode. To obtain the bytecode, call <code>toBytecode()</code>: byte[] b = cc.toBytecode(); </pre></ul> +<p>You can directly load the <code>CtClass</code> as well: + +<ul><pre> +Class clazz = cc.toClass(); +</pre></ul> + +<p><code>toClass()</code> requests the context class loader for the current +thread to load the class file represented by the <code>CtClass</code>. It +returns a <code>java.lang.Class</code> object representing the loaded class. +For more details, please see <a href="#toclass">the following section</a>. + <a name="def"> <h4>Defining a new class</h4> @@ -483,7 +496,7 @@ the easiest way for modifying the classes is as follows: <code>ClassPool.get()</code>, <li>2. Modify it, and <li>3. Call <code>writeFile()</code> or <code>toBytecode()</code> - on that <code>CtClass</code> object. + on that <code>CtClass</code> object to obtain a modified class file. </ul> <p>If whether a class is modified or not is determined at load time, @@ -496,7 +509,9 @@ by Javassist. <p><br> +<a name="toclass"> <h3>3.1 The <code>toClass</code> method in <code>CtClass</code></h3> +</a> <p>The <code>CtClass</code> provides a convenience method <code>toClass()</code>, which requests the context class loader for |