更改字段类型后的 javassist NoSuchFieldError

javassist NoSuchFieldError after changing the type of a field

我目前正在研究 javassist 并遇到了这个问题。我正在尝试使用 javassist 更改字段类型。但是,当代码在我更改后尝试访问该字段时,结果是 NoSuchFieldException。

所以这是我要更改的 class:

public class AlterMe {
    private ClassA someField;
    public void doSomething() {
        someField.doSomething(Object someArg);
    }
}

下面是我的 ClassLoader 中进行实际更改的部分:

//...Left out all the boilerplate code for testing if its the right class
Class ctClass = ClassPool.getDefault().get(name);
ctClass.getField("SomeField").setType(ClassPool.getDefault().get("the.replacement.ClassB");
// I also do the instantiation inside the constructors
for (CtConstructor constructor : ctClass.getConstructors()) {
    constructor.insertBefore("someField = new the.replacement.ClassB();");
}

我还尝试了其他几种更改字段类型的方法。例如,我尝试删除该字段并添加一个同名字段,或者将对 someField 的调用重定向到我在使用正确类型之前添加的 someFieldNew。 所以当我 运行 doSomething() 现在,我得到这个异常:

Exception in thread "main" java.lang.NoSuchFieldError: someField

为了完整起见,我使用的是源代码级别 1.7 和 javassist 版本 3.21.0-GA。

我希望任何人都可以帮助解决这个问题,因为我确实被困在这里了。

好的,这是我终于找到的解决方案。这不是很好,但它有效。 而不是替换

的类型
someField

我添加了一个类型正确的字段,并使用 ExprEditor 更改了所有方法调用。这是代码:

CtField field = new CtField(ClassPool.getDefault().get("the.replacement.classB"), "classB", ctClass);
ctClass.addField(field, CtField.Initializer.byExpr("new the.replacement.classB()"));
for (CtMethod method : ctClass.getMethods()) {
    method.instrument(new ExprEditor() {
        public void edit(MethodCall methodCall) throws CannotCompileException {
           if (methodCall.getMethodName().equals("doSomething") && methodCall.getClassName().getClassName().equals("the.original.ClassA")) {
               methodCall.replace("classB.doSomething()");
           }
      }
}

我唯一注意到的是重载该方法不起作用。假设 ClassB 有方法

 doSomething(Object)
 doSomething(Sting)
 doSomething(int)

它将始终调用对象方法。但那是我可以忍受的。

如果有人知道更好的解决方案,我仍然希望看到它。