我目前正在搞乱javassist,并解决了这个问题。我正在尝试使用javassist更改字段类型。但是,当代码在我更改后尝试访问此字段时,结果是NoSuchFieldException。
所以这是我想要改变的课程:
//...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();");
}
这是我的ClassLoader做实际改变的部分:
Exception in thread "main" java.lang.NoSuchFieldError: someField
我还尝试了其他几种更改字段类型的方法。例如,我尝试删除该字段并使用相同的名称添加一个字段或将调用重定向到someField到someFieldNew,我在使用正确的类型之前添加了该字段。 所以当我现在运行doSomething()时,我得到了这个例外:
GoogleStorage
为了完整起见,我使用源级别1.7和javassist版本3.21.0-GA。
我希望有人可以帮忙解决这个问题,因为我肯定会被困在这里。
答案 0 :(得分:0)
好的,这是我最终找到的解决方案。这不好但是有效。
而不是替换的类型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($1)");
}
}
}
我注意到的唯一事情就是重载方法不起作用。假设ClassB有方法
doSomething(Object)
doSomething(Sting)
doSomething(int)
它将始终调用Object方法。但这就是我可以忍受的东西。
如果有人知道更好的解决方案,我仍然希望看到它。