0

I'm trying to replace a method declared in my main class using instrument. This piece of code will intercept all the method calls during the execution but it won't replace the method body for a certain method (change in my case)

BeanMain.java

package application;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

public class BeanMain {
    private Bean bean;

    public BeanMain(){
        bean = new Bean("old_a", "old_b");
    }

    public void print(){
        System.out.format("\n%-25s %5s  %5s\n", "[BeanMain]", bean.getA(), bean.getB());

    }

    public void change(String pre){
        bean.setParam(pre+"A", pre+"B");
    }

    public static void main(String[] args) throws NotFoundException, CannotCompileException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get("application.BeanMain");
        ctClass.instrument(new ExprEditor(){
            @Override
            public void edit(MethodCall m) throws CannotCompileException {
                System.out.println(m.getMethodName());
                if(m.getMethodName().equals("change"))
                    m.replace("{System.out.println(\"$1\"); $_ = $proceed($$);}");
            }
        });
        BeanMain inst = new BeanMain();
        inst.print();
        inst.change("new_");
        inst.print();
    }
}

Bean.java

package application;

public class Bean {
    private String a;
    private String b;

    public Bean(){}

    public Bean(String a, String b) {
        this.a = a;
        this.b = b;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public void setParam(String a, String b){
        this.a = a;
        this.b = b;
    }

    public void doSomething(){
        System.out.println("Doing something.");
    }
}

Is my problem class loading related?

Antonio Santoro
  • 827
  • 1
  • 11
  • 29
  • You have to make up your mind. Do you want to replace the method **call** or the method declaration’s **body**? – Holger Jul 16 '18 at 14:46
  • Let's say I want to replace the method call, is `replace()` method limited in this case? – Antonio Santoro Jul 17 '18 at 10:11
  • If you want to replace the method *call*, “it won't replace the method body” is not an error. Whether replacing the call works or not, is hard to tell. The only method call of a method named `change` happens within your `main` method which is already running. Instrumentation doesn’t replace ongoing executions of a method, only subsequent executions. – Holger Jul 17 '18 at 10:47
  • So, according to you last sentence, am I able to instrument a method called by a class loaded by the BeanMain class? – Antonio Santoro Jul 17 '18 at 16:18
  • I never used Javassist for that, so I can’t say anything about `CtClass.instrument`, but in principle, the Instrumentation facility of the HotSpot JVM is capable of replacing all methods for subsequent calls. So assuming that Javassist runs atop of that, it should be possible. It should even work, if you call your `main` method again after instrumenting it. – Holger Jul 17 '18 at 19:27

0 Answers0