add a useful CodeConverter method:redirectMethodCallToStatictags/rel_3_25_0_ga
@@ -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; | |||
@@ -406,6 +407,42 @@ public class CodeConverter { | |||
= new TransformCall(transformers, oldMethodName, newMethod); | |||
} | |||
/** | |||
* 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 |
@@ -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; | |||
} | |||
} |
@@ -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"); |
@@ -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); | |||
} | |||
} |