更改字段类型后的 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)
它将始终调用对象方法。但那是我可以忍受的。
如果有人知道更好的解决方案,我仍然希望看到它。
我目前正在研究 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)
它将始终调用对象方法。但那是我可以忍受的。
如果有人知道更好的解决方案,我仍然希望看到它。