Sunday, September 26, 2010

JAVASSIST (Java programming Assistant)

JAVASSIST (Java programming Assistant) is a utility that allows one to inspect, edit and create Java binary classes. It enables Java programs to define a new class at runtime and to modify a given class file when the JVM loads it. Its best feature is its ease of use since it allows developers to fully exploit byte code manipulation with little or no knowledge of byte code, giving them a degree of fine-grained control.

Javassist provides two levels of API: Source level and Byte code level. If the users use source level API, they can edit a class file without knowledge of the specifications of the Java byte code. The whole API is designed with only the vocabulary of the Java language. You can even specify inserted byte code in the form of source text; Javassist compiles it on the fly. On the other hand, the byte code level API allows the users to directly edit a class file as other editors.

Javassist uses the javassist.ClassPool class to track and control the classes being manipulated. Classes loaded in a class pool are represented by javassist.CtClass instances where as fields, methods and constructors are represented by javassist.CtField, javassist.CtMethod and javassist.CtConstructor instances, respectively.

An Example of Javassist

The below example depicts the usage of few of the Javassist basic APIs. All that is required is to just download ‘javassist.jar’ and add the same to the class path.





/***** Class file before modification –
ClassToBeModified.class – START *****/
class ClassToBeModified {
    ClassToBeModified() {  }
    public static void main(String args[])  {  }
    public static void methodToBeModified() {
        System.out.println("***** Sample Program for JAVASSIST *****");
    }
}
/***** Class file before modification – ClassToBeModified.class – END *****/
 
/***** Code to modify the above class file – ClassJavaAssist.class – START *****/
import javassist.*;
import java.io.IOException;
  
class ClassJavaAssist {
    public static void main(String[] a) throws NotFoundException,
    CannotCompileException {
    /** Gets the class pool object */
     ClassPool cPool = ClassPool.getDefault();
     /** Gets the handle to the class to be modified */
     CtClass ctCls = cPool.get("ClassToBeModified");
     CtMethod ctMethod = null;
       /** Sets the class level modifier */
     ctCls.setModifiers(Modifier.PUBLIC);
       /** Modifies the name of the class */
     ctCls.replaceClassName("ClassToBeModified", "ClassModified");
       /** Modifies the name of the method */
     ctMethod = ctCls.getDeclaredMethod("methodToBeModified");
     ctMethod.setName("methodModified");
       /** Sets the content for the main method */
     ctMethod = ctCls.getDeclaredMethod("main");
     ctMethod.setBody("methodModified();");
       /** Adds a new method to the class */
     ctMethod = CtNewMethod.make("public static void sayHello() {}", ctCls);
     ctCls.addMethod(ctMethod);
     /** Sets the content for the new method */
     ctMethod = ctCls.getDeclaredMethod("sayHello");
     ctMethod.setBody("System.out.println(\"How are you?\");");

     /** Adds a method call to the main method */
     ctMethod = ctCls.getDeclaredMethod("main");
     ctMethod.insertAfter("sayHello();");
     /** Adds more content to the existing method */
     ctMethod = ctCls.getDeclaredMethod("sayHello");
     ctMethod.insertBefore("System.out.println(\"Hello All ... \");");
     try {
      /** Writes the modified class file */
      ctCls.writeFile();
     } catch (IOException ioEx) {
      /** Throw an IO Exception */
      ioEx.printStackTrace();
     } catch (Exception ex) {
      /** Throw an Exception */
     ex.printStackTrace();
     }
    }
}
/***** Code to modify the above class file – ClassJavaAssist.class – END *****/
  
/***** Class file after modification – ClassModified.class – START *****/
public class ClassModified {
    ClassModified() {  }
    public static void main(String args[]) {
        methodModified();
        sayHello();
    }
  
    public static void methodModified() {
        System.out.println("***** Sample Program for JAVASSIST *****");
    }
  
    public static void sayHello() {
        System.out.println("Hello All ... ");
        System.out.println("How are you?");
    }
}
/***** Class file after modification – ClassModified.class – END *****/


Advantages
• One can use Javassist to alter the byte code of a Java class without actually needing to learn anything about byte code or the Java Virtual Machine (JVM) architecture.
• Javassist can be a good tool for adding new methods into a class and for inserting before/after/around advice at the both caller and called sides.
• Javassist enables Java programs to use a metaobject that controls method calls on base-level objects. No specialized compiler or virtual machine are needed.
• Javassist enables applets to call a method on a remote object running on the web server. Unlike the Java RMI, the programmer does not need a stub compiler such as RMIC; the stub code is dynamically produced by Javassist.

You must be wondering, what's the use case of this.

Check this out...

http://java.dzone.com/articles/injecting-better-logging

1 comment:

  1. I wonder if it would be possible to obtain the modified source code in order to perform java source code manipulation. Maybe, we can use the method toString() in CtClass.

    ReplyDelete