javassist

Class CodeConverter

public class CodeConverter extends Object

Simple translator of method bodies (also see the 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:

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
interfaceCodeConverter.ArrayAccessReplacementMethodNames
Interface containing the method names to be used as array access replacements.
static classCodeConverter.DefaultArrayAccessReplacementMethodNames
Default implementation of the ArrayAccessReplacementMethodNames interface giving default values for method names to be used for replacing accesses to array elements.
Method Summary
voidinsertAfterMethod(CtMethod origMethod, CtMethod afterMethod)
Inserts a call to another method after an existing method call.
voidinsertBeforeMethod(CtMethod origMethod, CtMethod beforeMethod)
Insert a call to another method before an existing method call.
voidredirectFieldAccess(CtField field, CtClass newClass, String newFieldname)
Modify a method body so that field read/write expressions access a different field from the original one.
voidredirectMethodCall(CtMethod origMethod, CtMethod substMethod)
Modify method invocations in a method body so that a different method will be invoked.
voidredirectMethodCall(String oldMethodName, CtMethod newMethod)
Correct invocations to a method that has been renamed.
voidreplaceArrayAccess(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.
voidreplaceFieldRead(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.
voidreplaceFieldWrite(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.
voidreplaceNew(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.

Method Detail

insertAfterMethod

public void insertAfterMethod(CtMethod origMethod, CtMethod afterMethod)
Inserts a call to another method after an existing method call. That "after" method must be static. The return type must be 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():

Then the after method must be something like this:

The CodeConverter would translate bytecode equivalent to:

into the bytecode equivalent to:

Parameters: origMethod the method originally invoked. afterMethod the method invoked after origMethod.

insertBeforeMethod

public void insertBeforeMethod(CtMethod origMethod, CtMethod beforeMethod)
Insert a call to another method before an existing method call. That "before" method must be static. The return type must be 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():

Then the before method must be something like this:

The CodeConverter would translate bytecode equivalent to:

into the bytecode equivalent to:

Parameters: origMethod the method originally invoked. beforeMethod the method invoked before origMethod.

redirectFieldAccess

public 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.

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.

redirectMethodCall

public void redirectMethodCall(CtMethod origMethod, CtMethod substMethod)
Modify method invocations in a method body so that a different method will be invoked.

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

redirectMethodCall

public void redirectMethodCall(String oldMethodName, CtMethod newMethod)
Correct invocations to a method that has been renamed. If a method is renamed, calls to that method must be also modified so that the method with the new name will be called.

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

replaceArrayAccess

public 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. In the case of reading an element from the array, this is replaced with a call to a static method with the array and the index as arguments, the return value is the value read from the array. If writing to an array, this is replaced with a call to a static method with the array, index and new value as parameters, the return value of the static method is 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.

See Also:

replaceFieldRead

public 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. This static method receives the target object of the original read expression as a parameter. It must return a value of the same type as the field.

For example, the program below

can be translated into:

where

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.

replaceFieldWrite

public 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. This static method receives two parameters: the target object of the original write expression and the assigned value. The return type of the static method is void.

For example, the program below

can be translated into:

where

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

public 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. For example, replaceNew(ctPoint, ctSingleton, "createPoint") (where ctPoint and ctSingleton are compile-time classes for class Point and class Singleton, respectively) replaces all occurrences of: in the method body with:

This enables to intercept instantiation of Point and change the samentics. For example, the following createPoint() implements the singleton pattern:

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.

Javassist, a Java-bytecode translator toolkit.
Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.