aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshifujun <shifujun@foxmail.com>2019-02-01 17:26:07 +0800
committershifujun <shifujun@foxmail.com>2019-02-01 17:33:00 +0800
commitc85bc4f090044d657419f82b5fc33434ab911c62 (patch)
tree0ab0bd3ecc8d9370abb62f4ea13df00fb8e19bf9
parent6ea8021f1517ee2923bd5d50dc466594ac7f68bf (diff)
downloadjavassist-c85bc4f090044d657419f82b5fc33434ab911c62.tar.gz
javassist-c85bc4f090044d657419f82b5fc33434ab911c62.zip
add a new CodeConverter method:redirectMethodCallToStatic
-rw-r--r--src/main/javassist/CodeConverter.java37
-rw-r--r--src/main/javassist/convert/TransformCallToStatic.java29
-rw-r--r--src/test/javassist/JvstTest3.java14
-rw-r--r--src/test/test3/MethodRedirectToStatic.java22
4 files changed, 102 insertions, 0 deletions
diff --git a/src/main/javassist/CodeConverter.java b/src/main/javassist/CodeConverter.java
index 6df3622c..10d7ddad 100644
--- a/src/main/javassist/CodeConverter.java
+++ b/src/main/javassist/CodeConverter.java
@@ -25,6 +25,7 @@ import javassist.convert.TransformAccessArrayField;
import javassist.convert.TransformAfter;
import javassist.convert.TransformBefore;
import javassist.convert.TransformCall;
+import javassist.convert.TransformCallToStatic;
import javassist.convert.TransformFieldAccess;
import javassist.convert.TransformNew;
import javassist.convert.TransformNewClass;
@@ -407,6 +408,42 @@ public class CodeConverter {
}
/**
+ * Redirect non-static method invocations in a method body to a static
+ * method. The return type must be same with the originally invoked method.
+ * As parameters, the static method receives
+ * the target object and all the parameters to the originally invoked
+ * method. For example, if the originally invoked method is
+ * <code>move()</code>:
+ *
+ * <pre>class Point {
+ * Point move(int x, int y) { ... }
+ * }</pre>
+ *
+ * <p>Then the static method must be something like this:
+ *
+ * <pre>class Verbose {
+ * static Point print(Point target, int x, int y) { ... }
+ * }</pre>
+ *
+ * <p>The <code>CodeConverter</code> would translate bytecode
+ * equivalent to:
+ *
+ * <pre>Point p2 = p.move(x + y, 0);</pre>
+ *
+ * <p>into the bytecode equivalent to:
+ *
+ * <pre>Point p2 = Verbose.print(p, x + y, 0);</pre>
+ *
+ * @param origMethod original method
+ * @param staticMethod static method
+ */
+ public void redirectMethodCallToStatic(CtMethod origMethod,
+ CtMethod staticMethod) {
+ transformers = new TransformCallToStatic(transformers, origMethod,
+ staticMethod);
+ }
+
+ /**
* Insert a call to another method before an existing method call.
* That "before" method must be static. The return type must be
* <code>void</code>. As parameters, the before method receives
diff --git a/src/main/javassist/convert/TransformCallToStatic.java b/src/main/javassist/convert/TransformCallToStatic.java
new file mode 100644
index 00000000..87181edf
--- /dev/null
+++ b/src/main/javassist/convert/TransformCallToStatic.java
@@ -0,0 +1,29 @@
+package javassist.convert;
+
+import javassist.CtMethod;
+import javassist.bytecode.BadBytecode;
+import javassist.bytecode.CodeIterator;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.Descriptor;
+import javassist.bytecode.Opcode;
+
+public class TransformCallToStatic extends TransformCall {
+ public TransformCallToStatic(Transformer next, CtMethod origMethod, CtMethod substMethod) {
+ super(next, origMethod, substMethod);
+ methodDescriptor = origMethod.getMethodInfo2().getDescriptor();
+ }
+
+ @Override
+ protected int match(int c, int pos, CodeIterator iterator, int typedesc, ConstPool cp) {
+ if (newIndex == 0) {
+ String desc = Descriptor.insertParameter(classname, methodDescriptor);
+ int nt = cp.addNameAndTypeInfo(newMethodname, desc);
+ int ci = cp.addClassInfo(newClassname);
+ newIndex = cp.addMethodrefInfo(ci, nt);
+ constPool = cp;
+ }
+ iterator.writeByte(Opcode.INVOKESTATIC, pos);
+ iterator.write16bit(newIndex, pos + 1);
+ return pos;
+ }
+}
diff --git a/src/test/javassist/JvstTest3.java b/src/test/javassist/JvstTest3.java
index 46f06b16..c065170c 100644
--- a/src/test/javassist/JvstTest3.java
+++ b/src/test/javassist/JvstTest3.java
@@ -586,6 +586,20 @@ public class JvstTest3 extends JvstTestRoot {
assertEquals(524, invoke(obj, "test"));
}
+ public void testMethodRedirectToStatic() throws Exception {
+ CtClass targetClass = sloader.get("test3.MethodRedirectToStatic");
+ CtClass staticClass = sloader.get("test3.MethodRedirectToStatic2");
+ CtMethod targetMethod = targetClass.getDeclaredMethod("add");
+ CtMethod staticMethod = staticClass.getDeclaredMethod("add2");
+ CodeConverter conv = new CodeConverter();
+
+ conv.redirectMethodCallToStatic(targetMethod, staticMethod);
+ targetClass.instrument(conv);
+ targetClass.writeFile();
+ Object obj = make(targetClass.getName());
+ assertEquals(30, invoke(obj, "test"));
+ }
+
public void testClassMap() throws Exception {
ClassMap map = new ClassMap();
map.put("aa", "AA");
diff --git a/src/test/test3/MethodRedirectToStatic.java b/src/test/test3/MethodRedirectToStatic.java
new file mode 100644
index 00000000..f1d68e35
--- /dev/null
+++ b/src/test/test3/MethodRedirectToStatic.java
@@ -0,0 +1,22 @@
+package test3;
+
+public class MethodRedirectToStatic {
+
+ public static void main(String[] args) {
+ System.out.println(new MethodRedirectToStatic().test());
+ }
+
+ int add(int a, int b) {
+ return a + b;
+ }
+
+ public int test() {
+ return add(1, 2);
+ }
+}
+
+class MethodRedirectToStatic2 {
+ public static int add2(MethodRedirectToStatic target, int a, int b) {
+ return target.add(a * 10, b * 10);
+ }
+}