Add a field and change its value dynamically using Javassist

In the example below, I want to execute the super method of class A by not executing the super method of class B. For this, I am using Javassist and I am able to do so with the help of this SO post. But I am unable to pass a value when calling the super method of class A. I have provided a variable name as parameter, while calling hi() of class C in the example below but that is not being referred in the variable myVar that I am generating using Javassist.

The generated output:

Ok thing C MyData
Important thing A null

Expected output:

Ok thing C MyData
Important thing A MyData

Any help will be very much appreciated.

Source Code:

class A {
    public void hi(String first) {
        System.out.println("Want Important thing A " + first);
    }
}

class B extends A {
    public void hi(String second) {
        System.out.println("Don't want TERRIBLE THING B " + second);
        super.hi(second);
    }
}

class C extends B {
    public void hi(String third) {
        System.out.println("Want important thing C " + third);
        super.hi(third);
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        String name = "MyData";
        CtClass cc = ClassPool.getDefault().get("mypackage.B");
        CtMethod m1 = cc.getDeclaredMethod("hi");
        cc.removeMethod(m1);
        CtMethod m2 = CtNewMethod.copy(m1, cc, null);
        CtClass stringVar = ClassPool.getDefault().get("java.lang.String");
        CtField f = new CtField(stringVar , "myVar", cc);
        cc.addField(f);
        m2.setBody("{ /* override method B.hi() body */ return super.hi(myVar);}", "this", m1.getName());
        cc.addMethod(m2);
        cc.toClass();
        C obj = new C();
        obj.hi(name);
    }
}

Answer

Since you want to pass the parameter value to the super method call, you don’t need to introduce a new field.

According to this tutorial you can refer to the first parameter using $1, regardless of the original source code’s name (which also solves the problem that the name might not be stored in the class file).

So the method body would look like "{ return super.hi($1); }". The tutorial also explains that Javassist, unlike ordinary Java source code, allows to use this syntax for void methods.

It’s important to keep in mind that the method of replacing classes by materializing an alternative version before the other has been loaded, is very fragile, especially when being done in the same method that also uses the changed class (or a subclass of it). This depends on the precise time of class loading whose subtleties have been discussed in When is a Java Class loaded?