diff options
author | Shigeru Chiba <chiba@chibas.net> | 2015-03-16 21:49:16 +0900 |
---|---|---|
committer | Shigeru Chiba <chiba@chibas.net> | 2015-03-16 21:49:16 +0900 |
commit | bbecd7c489662c68af12b0e56265d52b7b2a644d (patch) | |
tree | 338a3fc7f1831eb57d80855f94819eea392d8775 | |
parent | d045a7f1ec0e5f2067459352426a4c987c4a1a7a (diff) | |
parent | 7bb3c3936757923e69d1c10c914ead32b9399eee (diff) | |
download | javassist-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.java | 154 | ||||
-rw-r--r-- | src/test/javassist/tools/CallbackTest.java | 40 | ||||
-rw-r--r-- | src/test/test/javassist/tools/DummyClass.java | 8 |
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(){} +} |