From 1025384fe04e05dee846b8db3fd6c9de853c7012 Mon Sep 17 00:00:00 2001 From: =?utf8?q?M=C3=A5rten=20Hedborg?= Date: Fri, 28 Nov 2014 13:50:50 +0100 Subject: [PATCH] Added call back feature to CtBehaviour --- src/main/javassist/CtBehavior.java | 108 +++++++++++++++++++++++++ src/main/javassist/tools/Callback.java | 39 +++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/main/javassist/tools/Callback.java diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index 92513159..e52fcb79 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -20,6 +20,7 @@ import javassist.bytecode.*; import javassist.compiler.Javac; import javassist.compiler.CompileError; import javassist.expr.ExprEditor; +import javassist.tools.Callback; /** * CtBehavior represents a method, a constructor, @@ -713,6 +714,29 @@ public abstract class CtBehavior extends CtMember { declaringClass.checkModify(); } + /** + * Inserts callback at the beginning of the body. + * + *

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 insertBeforeBody() in CtConstructor. + * + * @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. * @@ -778,6 +802,39 @@ 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. @@ -1134,6 +1191,29 @@ public abstract class CtBehavior extends CtMember { return insertAt(lineNum, true, src); } + /** + * Inserts callback bytecode at the specified line in the body. + * It is equivalent to: + * + *
insertAt(lineNum, true, src) + * + *
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. * @@ -1210,4 +1290,32 @@ public abstract class CtBehavior extends CtMember { throw new CannotCompileException(e); } } + + /** + * Inserts callback bytecode at the specified line in the body. + * + *

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 + * modify set to false. + * + * @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 new file mode 100644 index 00000000..0cf5db47 --- /dev/null +++ b/src/main/javassist/tools/Callback.java @@ -0,0 +1,39 @@ +package javassist.tools; + +import java.util.HashMap; +import java.util.UUID; + +/** + * Creates bytecode that when executed calls back to the objects result method. + */ +public abstract class Callback { + + public static HashMap callbacks = new HashMap(); + + private final String callbackCode; + + /** + * Constructs a new Callback object. + * + * @param src java code that returns one or many objects. if many objects + * are returned they should 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+"});"; + } + + /** + * 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 + */ + public abstract void result(Object... objects); + + @Override + public String toString(){ + return callbackCode; + } +} -- 2.39.5