javassist
public class CodeConverter extends Object
javassist.expr
package).
Instances of this class specifies how to instrument of the
bytecodes representing a method body. They are passed to
CtClass.instrument()
or
CtMethod.instrument()
as a parameter.
Example:
ClassPool cp = ClassPool.getDefault(); CtClass point = cp.get("Point"); CtClass singleton = cp.get("Singleton"); CtClass client = cp.get("Client"); CodeConverter conv = new CodeConverter(); conv.replaceNew(point, singleton, "makePoint"); client.instrument(conv);
This program substitutes "Singleton.makePoint()
"
for all occurrences of "new Point()
"
appearing in methods declared in a Client
class.
See Also: instrument CtMethod ExprEditor
Nested Class Summary | |
---|---|
interface | CodeConverter.ArrayAccessReplacementMethodNames
Interface containing the method names to be used
as array access replacements.
|
static class | CodeConverter.DefaultArrayAccessReplacementMethodNames
Default implementation of the ArrayAccessReplacementMethodNames
interface giving default values for method names to be used for replacing
accesses to array elements.
|
Method Summary | |
---|---|
void | insertAfterMethod(CtMethod origMethod, CtMethod afterMethod)
Inserts a call to another method after an existing method call.
|
void | insertBeforeMethod(CtMethod origMethod, CtMethod beforeMethod)
Insert a call to another method before an existing method call.
|
void | redirectFieldAccess(CtField field, CtClass newClass, String newFieldname)
Modify a method body so that field read/write expressions access
a different field from the original one.
|
void | redirectMethodCall(CtMethod origMethod, CtMethod substMethod)
Modify method invocations in a method body so that a different
method will be invoked.
|
void | redirectMethodCall(String oldMethodName, CtMethod newMethod)
Correct invocations to a method that has been renamed.
|
void | replaceArrayAccess(CtClass calledClass, CodeConverter.ArrayAccessReplacementMethodNames names)
Modify a method body, so that ALL accesses to an array are replaced with
calls to static methods within another class. |
void | replaceFieldRead(CtField field, CtClass calledClass, String calledMethod)
Modify a method body so that an expression reading the specified
field is replaced with a call to the specified static method.
|
void | replaceFieldWrite(CtField field, CtClass calledClass, String calledMethod)
Modify a method body so that an expression writing the specified
field is replaced with a call to the specified static method.
|
void | replaceNew(CtClass newClass, CtClass calledClass, String calledMethod)
Modify a method body so that instantiation of the specified class
is replaced with a call to the specified static method. |
void
. As parameters, the after method receives
the target object and all the parameters to the originally invoked
method. For example, if the originally invoked method is
move()
:
class Point { Point move(int x, int y) { ... } }
Then the after method must be something like this:
class Verbose { static void print(Point target, int x, int y) { ... } }
The CodeConverter
would translate bytecode
equivalent to:
Point p2 = p.move(x + y, 0);
into the bytecode equivalent to:
int tmp1 = x + y; int tmp2 = 0; Point p2 = p.move(tmp1, tmp2); Verbose.print(p, tmp1, tmp2);
Parameters: origMethod the method originally invoked. afterMethod the method invoked after
origMethod
.
void
. As parameters, the before method receives
the target object and all the parameters to the originally invoked
method. For example, if the originally invoked method is
move()
:
class Point { Point move(int x, int y) { ... } }
Then the before method must be something like this:
class Verbose { static void print(Point target, int x, int y) { ... } }
The CodeConverter
would translate bytecode
equivalent to:
Point p2 = p.move(x + y, 0);
into the bytecode equivalent to:
int tmp1 = x + y; int tmp2 = 0; Verbose.print(p, tmp1, tmp2); Point p2 = p.move(tmp1, tmp2);
Parameters: origMethod the method originally invoked. beforeMethod the method invoked before
origMethod
.
Note that this method changes only the filed name and the class declaring the field; the type of the target object does not change. Therefore, the substituted field must be declared in the same class or a superclass of the original class.
Also, clazz
and newClass
must specify
the class directly declaring the field. They must not specify
a subclass of that class.
Parameters: field the originally accessed field. newClass the class declaring the substituted field. newFieldname the name of the substituted field.
Note that the target object, the parameters, or the type of invocation (static method call, interface call, or private method call) are not modified. Only the method name is changed. The substituted method must have the same signature that the original one has. If the original method is a static method, the substituted method must be static.
Parameters: origMethod original method substMethod substituted method
The method must be declared in the same class before and after it is renamed.
Note that the target object, the parameters, or the type of invocation (static method call, interface call, or private method call) are not modified. Only the method name is changed.
Parameters: oldMethodName the old name of the method. newMethod the method with the new name.
See Also: setName
void
.
The calledClass
parameter is the class containing the static methods to be used
for array replacement. The names
parameter points to an implementation of
ArrayAccessReplacementMethodNames
which specifies the names of the method to be
used for access for each type of array. For example reading from an int[]
will
require a different method than if writing to an int[]
, and writing to a long[]
will require a different method than if writing to a byte[]
. If the implementation
of ArrayAccessReplacementMethodNames
does not contain the name for access for a
type of array, that access is not replaced.
A default implementation of ArrayAccessReplacementMethodNames
called
DefaultArrayAccessReplacementMethodNames
has been provided and is what is used in the
following example. This also assumes that 'foo.ArrayAdvisor'
is the name of the
CtClass
passed in.
If we have the following class:
class POJO{ int[] ints = new int[]{1, 2, 3, 4, 5}; long[] longs = new int[]{10, 20, 30}; Object objects = new Object[]{true, false}; Integer[] integers = new Integer[]{new Integer(10)}; }and this is accessed as:
POJO p = new POJO(); //Write to int array p.ints[2] = 7; //Read from int array int i = p.ints[2]; //Write to long array p.longs[2] = 1000L; //Read from long array long l = p.longs[2]; //Write to Object array p.objects[2] = "Hello"; //Read from Object array Object o = p.objects[2]; //Write to Integer array Integer integer = new Integer(5); p.integers[0] = integer; //Read from Object array integer = p.integers[0];Following instrumentation we will have
POJO p = new POJO(); //Write to int array ArrayAdvisor.arrayWriteInt(p.ints, 2, 7); //Read from int array int i = ArrayAdvisor.arrayReadInt(p.ints, 2); //Write to long array ArrayAdvisor.arrayWriteLong(p.longs, 2, 1000L); //Read from long array long l = ArrayAdvisor.arrayReadLong(p.longs, 2); //Write to Object array ArrayAdvisor.arrayWriteObject(p.objects, 2, "Hello"); //Read from Object array Object o = ArrayAdvisor.arrayReadObject(p.objects, 2); //Write to Integer array Integer integer = new Integer(5); ArrayAdvisor.arrayWriteObject(p.integers, 0, integer); //Read from Object array integer = ArrayAdvisor.arrayWriteObject(p.integers, 0);
Parameters: calledClass the class containing the static methods. names contains the names of the methods to replace the different kinds of array access with.
For example, the program below
Point p = new Point(); int newX = p.x + 3;
can be translated into:
Point p = new Point(); int newX = Accessor.readX(p) + 3;
where
public class Accessor { public static int readX(Object target) { ... } }
The type of the parameter of readX()
must
be java.lang.Object
independently of the actual
type of target
. The return type must be the same
as the field type.
Parameters: field the field. calledClass the class in which the static method is declared. calledMethod the name of the static method.
void
.
For example, the program below
Point p = new Point(); p.x = 3;
can be translated into:
Point p = new Point(); Accessor.writeX(3);
where
public class Accessor { public static void writeX(Object target, int value) { ... } }
The type of the first parameter of writeX()
must
be java.lang.Object
independently of the actual
type of target
. The type of the second parameter
is the same as the field type.
Parameters: field the field. calledClass the class in which the static method is declared. calledMethod the name of the static method.
replaceNew(ctPoint, ctSingleton, "createPoint")
(where ctPoint
and ctSingleton
are
compile-time classes for class Point
and class
Singleton
, respectively)
replaces all occurrences of:
new Point(x, y)
Singleton.createPoint(x, y)
This enables to intercept instantiation of Point
and change the samentics. For example, the following
createPoint()
implements the singleton pattern:
public static Point createPoint(int x, int y) { if (aPoint == null) aPoint = new Point(x, y); return aPoint; }
The static method call substituted for the original new
expression must be
able to receive the same set of parameters as the original
constructor. If there are multiple constructors with different
parameter types, then there must be multiple static methods
with the same name but different parameter types.
The return type of the substituted static method must be
the exactly same as the type of the instantiated class specified by
newClass
.
Parameters: newClass the instantiated class. calledClass the class in which the static method is declared. calledMethod the name of the static method.