aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main/javassist/CtBehavior.java39
-rw-r--r--src/main/javassist/CtConstructor.java99
-rw-r--r--src/main/javassist/CtMethod.java40
-rw-r--r--src/main/javassist/bytecode/CodeIterator.java18
-rw-r--r--src/main/javassist/bytecode/Descriptor.java81
-rw-r--r--tutorial/tutorial.html17
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