aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShigeru Chiba <chiba@chibas.net>2015-03-16 21:49:16 +0900
committerShigeru Chiba <chiba@chibas.net>2015-03-16 21:49:16 +0900
commitbbecd7c489662c68af12b0e56265d52b7b2a644d (patch)
tree338a3fc7f1831eb57d80855f94819eea392d8775
parentd045a7f1ec0e5f2067459352426a4c987c4a1a7a (diff)
parent7bb3c3936757923e69d1c10c914ead32b9399eee (diff)
downloadjavassist-bbecd7c489662c68af12b0e56265d52b7b2a644d.tar.gz
javassist-bbecd7c489662c68af12b0e56265d52b7b2a644d.zip
Merge pull request #26 from m8rten/master
Added call back feature to CtBehaviour
-rw-r--r--src/main/javassist/tools/Callback.java154
-rw-r--r--src/test/javassist/tools/CallbackTest.java40
-rw-r--r--src/test/test/javassist/tools/DummyClass.java8
3 files changed, 202 insertions, 0 deletions
diff --git a/src/main/javassist/tools/Callback.java b/src/main/javassist/tools/Callback.java
new file mode 100644
index 00000000..26a4200e
--- /dev/null
+++ b/src/main/javassist/tools/Callback.java
@@ -0,0 +1,154 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later,
+ * or the Apache License Version 2.0.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+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 instance's result method.
+ *
+ * Example of how to create and insert a callback:
+ * <pre>{@code
+ * ctMethod.insertAfter(new Callback("Thread.currentThread()") {
+ * @literal@Override
+ * public void result(Object... objects) {
+ * Thread thread = (Thread) objects[0];
+ * // do something with thread...
+ * }
+ * }.sourceCode());
+ * }</pre>
+ * Contains utility methods for inserts callbacks in <code>CtBehaviour</code>, example:
+ * <pre>{@code
+ * insertAfter(ctBehaviour, new Callback("Thread.currentThread(), dummyString") {
+ * @literal@Override
+ * public void result(Object... objects) {
+ * Thread thread = (Thread) objects[0];
+ * // do something with thread...
+ * }
+ * });
+ * }</pre>
+ *
+ * @author Marten Hedborg
+ */
+public abstract class Callback {
+
+ public static HashMap<String, Callback> callbacks = new HashMap<String, Callback>();
+
+ private final String sourceCode;
+
+ /**
+ * Constructs a new <code>Callback</code> object.
+ *
+ * @param src The source code representing the inserted callback bytecode.
+ * Can be one or many single statements each returning one object.
+ * If many single statements are used they must be comma separated.
+ */
+ public Callback(String src){
+ String uuid = UUID.randomUUID().toString();
+ callbacks.put(uuid, this);
+ sourceCode = "((javassist.tools.Callback) javassist.tools.Callback.callbacks.get(\""+uuid+"\")).result(new Object[]{"+src+"});";
+ }
+
+ /**
+ * Gets called when bytecode is executed
+ *
+ * @param objects Objects that the bytecode in callback returns
+ */
+ public abstract void result(Object... objects);
+
+ @Override
+ public String toString(){
+ return sourceCode();
+ }
+
+ public String sourceCode(){
+ return sourceCode;
+ }
+
+ /**
+ * Utility method to insert 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());
+ }
+
+ /**
+ * Utility method to 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);
+ }
+
+ /**
+ * Utility method to 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);
+ }
+
+ /**
+ * Utility method to 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..96632bda
--- /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(){}
+}