diff options
-rw-r--r-- | src/main/javassist/CtBehavior.java | 108 | ||||
-rw-r--r-- | src/main/javassist/tools/Callback.java | 95 | ||||
-rw-r--r-- | src/test/javassist/tools/CallbackTest.java | 40 | ||||
-rw-r--r-- | src/test/test/javassist/tools/DummyClass.java | 8 |
4 files changed, 135 insertions, 116 deletions
diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index e52fcb79..92513159 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -20,7 +20,6 @@ import javassist.bytecode.*; import javassist.compiler.Javac; import javassist.compiler.CompileError; import javassist.expr.ExprEditor; -import javassist.tools.Callback; /** * <code>CtBehavior</code> represents a method, a constructor, @@ -715,29 +714,6 @@ public abstract class CtBehavior extends CtMember { } /** - * Inserts callback at the beginning of the body. - * - * <p>If this object represents a constructor, - * the callback is inserted before - * a constructor in the super class or this class is called. - * Therefore, the inserted callback is subject to constraints described - * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed). - * For example, it cannot access instance fields or methods although - * it may assign a value to an instance field directly declared in this - * class. Accessing static fields and methods is allowed. - * Use <code>insertBeforeBody()</code> in <code>CtConstructor</code>. - * - * @param callback the source code representing the inserted bytecode. - * It must be a single statement or block. - * @see CtConstructor#insertBeforeBody(String) - */ - public void insertBefore(Callback callback) - throws CannotCompileException - { - insertBefore(callback.toString(), true); - } - - /** * Inserts bytecode at the beginning of the body. * * <p>If this object represents a constructor, @@ -803,39 +779,6 @@ public abstract class CtBehavior extends CtMember { } /** - * Inserts callback bytecode at the end of the body. - * The callback is inserted just before every return insturction. - * It is not executed when an exception is thrown. - * - * @param callback the source code representing the inserted bytecode. - * It must be a single statement or block. - */ - public void insertAfter(Callback callback) - throws CannotCompileException - { - insertAfter(callback.toString(), false); - } - - /** - * Inserts callback bytecode at the end of the body. - * The callback is inserted just before every return insturction. - * It is not executed when an exception is thrown. - * - * @param callback the callback source code representing the inserted bytecode. - * It must be a single statement or block. - * @param asFinally true if the inserted bytecode is executed - * not only when the control normally returns - * but also when an exception is thrown. - * If this parameter is true, the inserted code cannot - * access local variables. - */ - public void insertAfter(Callback callback, boolean asFinally) - throws CannotCompileException - { - insertAfter(callback.toString(), asFinally); - } - - /** * Inserts bytecode at the end of the body. * The bytecode is inserted just before every return insturction. * It is not executed when an exception is thrown. @@ -1192,29 +1135,6 @@ public abstract class CtBehavior extends CtMember { } /** - * Inserts callback bytecode at the specified line in the body. - * It is equivalent to: - * - * <br><code>insertAt(lineNum, true, src)</code> - * - * <br>See this method as well. - * - * @param lineNum the line number. The bytecode is inserted at the - * beginning of the code at the line specified by this - * line number. - * @param callback the callback source code representing the inserted bytecode. - * It must be a single statement or block. - * @return the line number at which the callback bytecode has been inserted. - * - * @see CtBehavior#insertAt(int,boolean,String) - */ - public int insertAt(int lineNum, Callback callback) - throws CannotCompileException - { - return insertAt(lineNum, true, callback.toString()); - } - - /** * Inserts bytecode at the specified line in the body. * * <p>If there is not @@ -1290,32 +1210,4 @@ public abstract class CtBehavior extends CtMember { throw new CannotCompileException(e); } } - - /** - * Inserts callback bytecode at the specified line in the body. - * - * <p>If there is not - * a statement at the specified line, the bytecode might be inserted - * at the line including the first statement after that line specified. - * For example, if there is only a closing brace at that line, the - * bytecode would be inserted at another line below. - * To know exactly where the bytecode will be inserted, call with - * <code>modify</code> set to <code>false</code>. - * - * @param lineNum the line number. The bytecode is inserted at the - * beginning of the code at the line specified by this - * line number. - * @param modify if false, this method does not insert the bytecode. - * It instead only returns the line number at which - * the bytecode would be inserted. - * @param callback the callback source code representing the inserted bytecode. - * It must be a single statement or block. - * If modify is false, the value of src can be null. - * @return the line number at which the bytecode has been inserted. - */ - public int insertAt(int lineNum, boolean modify, Callback callback) - throws CannotCompileException - { - return insertAt(lineNum,modify,callback.toString()); - } } diff --git a/src/main/javassist/tools/Callback.java b/src/main/javassist/tools/Callback.java index 0cf5db47..4a1a491f 100644 --- a/src/main/javassist/tools/Callback.java +++ b/src/main/javassist/tools/Callback.java @@ -1,39 +1,118 @@ package javassist.tools; +import javassist.CannotCompileException; +import javassist.CtBehavior; + import java.util.HashMap; import java.util.UUID; /** - * Creates bytecode that when executed calls back to the objects result method. + * Creates bytecode that when executed calls back to the instance's result method. + * + * Inserts callbacks in <code>CtBehaviour</code> + * */ public abstract class Callback { public static HashMap<String, Callback> callbacks = new HashMap<String, Callback>(); - private final String callbackCode; + private final String sourceCode; /** * Constructs a new <code>Callback</code> object. * - * @param src java code that returns one or many objects. if many objects - * are returned they should be comma separated + * @param src The source code representing the inserted callback bytecode. + * Can be one or many single statements or blocks each returning one object. + * If many single statements or blocks are used they must be comma separated. */ public Callback(String src){ String uuid = UUID.randomUUID().toString(); callbacks.put(uuid, this); - callbackCode = "((javassist.tools.Callback) javassist.tools.Callback.callbacks.get(\""+uuid+"\")).result(new Object[]{"+src+"});"; + sourceCode = "((javassist.tools.Callback) javassist.tools.Callback.callbacks.get(\""+uuid+"\")).result(new Object[]{"+src+"});"; } /** * Gets called when bytecode is executed * - * @param objects java code that returns one or many objects. if many objects - * are returned they should be comma separated + * @param objects Objects that the bytecode in callback returns */ public abstract void result(Object... objects); @Override public String toString(){ - return callbackCode; + return sourceCode(); + } + + public String sourceCode(){ + return sourceCode; + } + + /** + * Inserts callback at the beginning of the body. + * + * @param callback The callback + * + * @see CtBehavior#insertBefore(String) + */ + public static void insertBefore(CtBehavior behavior, Callback callback) + throws CannotCompileException + { + behavior.insertBefore(callback.toString()); + } + + /** + * Inserts callback at the end of the body. + * The callback is inserted just before every return instruction. + * It is not executed when an exception is thrown. + * + * @param behavior The behaviour to insert callback in + * @param callback The callback + * + * @see CtBehavior#insertAfter(String, boolean) + */ + public static void insertAfter(CtBehavior behavior,Callback callback) + throws CannotCompileException + { + behavior.insertAfter(callback.toString(), false); + } + + /** + * Inserts callback at the end of the body. + * The callback is inserted just before every return instruction. + * It is not executed when an exception is thrown. + * + * @param behavior The behaviour to insert callback in + * @param callback The callback representing the inserted. + * @param asFinally True if the inserted is executed + * Not only when the control normally returns + * but also when an exception is thrown. + * If this parameter is true, the inserted code cannot + * access local variables. + * + * @see CtBehavior#insertAfter(String, boolean) + */ + public static void insertAfter(CtBehavior behavior, Callback callback, boolean asFinally) + throws CannotCompileException + { + behavior.insertAfter(callback.toString(), asFinally); + } + + /** + * Inserts callback at the specified line in the body. + * + * @param behavior The behaviour to insert callback in + * @param callback The callback representing. + * @param lineNum The line number. The callback is inserted at the + * beginning of the code at the line specified by this + * line number. + * + * @return The line number at which the callback has been inserted. + * + * @see CtBehavior#insertAt(int, String) + */ + public static int insertAt(CtBehavior behavior, Callback callback, int lineNum) + throws CannotCompileException + { + return behavior.insertAt(lineNum, callback.toString()); } } diff --git a/src/test/javassist/tools/CallbackTest.java b/src/test/javassist/tools/CallbackTest.java new file mode 100644 index 00000000..a37ee61d --- /dev/null +++ b/src/test/javassist/tools/CallbackTest.java @@ -0,0 +1,40 @@ +package javassist.tools; + +import javassist.*; +import junit.framework.TestCase; +import test.javassist.tools.DummyClass; + +import static javassist.tools.Callback.*; + +public class CallbackTest extends TestCase { + + public void testSomeCallbacks() throws Exception { + + // Get class and method to change + ClassPool pool = ClassPool.getDefault(); + CtClass classToChange = pool.get("test.javassist.tools.DummyClass"); + CtMethod methodToChange = classToChange.getDeclaredMethod("dummyMethod"); + + // Insert after + methodToChange.insertAfter(new Callback("Thread.currentThread(), dummyString") { + @Override + public void result(Object... objects) { + assertEquals(objects[0], Thread.currentThread()); + assertEquals(objects[1], "dummyStringValue"); + } + }.sourceCode()); + + // Insert after using utility method + insertAfter(methodToChange, new Callback("Thread.currentThread(), dummyString") { + @Override + public void result(Object... objects) { + assertEquals(objects[0], Thread.currentThread()); + assertEquals(objects[1], "dummyStringValue"); + } + }); + + // Change class and invoke method(); + classToChange.toClass(); + new DummyClass().dummyMethod(); + } +} diff --git a/src/test/test/javassist/tools/DummyClass.java b/src/test/test/javassist/tools/DummyClass.java new file mode 100644 index 00000000..020aa55d --- /dev/null +++ b/src/test/test/javassist/tools/DummyClass.java @@ -0,0 +1,8 @@ +package test.javassist.tools; + +public class DummyClass { + + private String dummyString = "dummyStringValue"; + + public void dummyMethod(){} +} |