Search code examples
javajavassist

Printing instance variable using javasssist


I have to modify the following class at runtime to print the value of instance variable 'count' at the end of each method.

package test.hib.javaassist;

import java.io.IOException;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

public class JavaAssistTest {

    int count;


    public void doSomething1(){
        count++;
    }

    public void doSomething2(){
        count++;
    }

    public void doSomething3(){
        count++;
    }

    public void doSomething4(){
        count++;
    }

}

Following is the main class, where i am trying to alter the byte code with the help of javaassist.

package test.hib.javaassist;

import java.io.IOException;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

public class Main {

    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {

        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("test.hib.javaassist.JavaAssistTest");
        CtMethod[] methods = cc.getDeclaredMethods();

        for(CtMethod method : methods){
            if(! (method.getName().equals("main"))){
                method.insertAfter("{System.out.println(count);}");
                //method.insertAfter("System.out.println($type);");
            }
        }

        cc.writeFile();

        System.out.println("Completed editting");

        JavaAssistTest test = new JavaAssistTest();
        test.doSomething1();
        test.doSomething2();
        test.doSomething3();
        test.doSomething4();

        System.out.println("Finished");

    }

}

Currently it is printing

Completed editting
Finished

i want it to print

Completed editting
1
2
3
4
Finished

Can you pointout the mistake in my code?


Solution

  • The Javassist API is a bit confusing here. Have a look at the implementation of writeFile. It is a shortcut for writeFile(".") which saves the class in your program directory and not on the class path. You expect it to override the original class file what this method does not do. Your system class loader will not be able to locate the updated class file.

    You can either manually save the class file at the right location using writeFile(String) or force the loading of the modified class by calling cc.toClass() which forces the loading of the modified class before your class loader looks it up manually.