我正在尝试在我的开发环境中模拟一些服务。 serviceFactory代码类似于:
public class ApiFacadeImpl implements ApiFacade {
private OneService oneService = null;
public OneService getOneService(){
if(oneService==null) {//some initialization steps }
return oneService;
}
}
我知道这家工厂没有很好的编码和设计。但是我不能修改它的代码。 我的想法是改变字节码,所以我可以将它重新定义为:
public class ApiFacadeImpl implements ApiFacade {
private OneService oneService = new MyMockOneService();
....
}
我的第一个是: 这可能使用javassist吗?怎么样?
由于我无法使用google使用javassist重新初始化字段,我尝试删除它并重新创建它:
CtField oneServiceField = cc.getDeclaredField("oneService");
cc.removeField(oneServiceField);
CtField f = CtField.make(String.format("private %s %s=new %s();",
oneServiceField.getType().getName(), "oneService",
mockClass.getCanonicalName()), cc);
cc.addField(f);
cc.toClass();
然后我得到了例外:
javassist.CannotCompileException: by java.lang.ClassFormatError: Invalid length 99 in LocalVariableTable in class file com/Test
at javassist.ClassPool.toClass(ClassPool.java:1051)
at javassist.ClassPool.toClass(ClassPool.java:994)
at javassist.ClassPool.toClass(ClassPool.java:952)
at javassist.CtClass.toClass(CtClass.java:1079)
我的第二个问题是为什么这个例外?哪一步不服从java类的定义?当我删除该字段时,javassist会帮助删除字段引用:
public OneService getOneService(){
if(oneService==null) {//some initialization steps }
return oneService;
}
非常感谢。
答案 0 :(得分:4)
对于问题#1,是的,您可以通过修改ApiFacadeImpl
的构造函数来实现此目的。请记住使用CtConstructor#insertAfter
附加赋值语句。
ClassPool pool = ClassPool.getDefault();
CtClass factoryClass = pool.getCtClass("ServiceFactory");
CtConstructor constructor = factoryClass.getDeclaredConstructor(null);
String setMockStatement = String.format("service = new %s();",
MockServiceImpl.class.getCanonicalName());
constructor.insertAfter(setMockStatement);
factoryClass.toClass();
new ServiceFactory().getService().say();
我尝试了你提出的方式。但是,它没有用。经过一些调试后,我发现如果我们删除一个字段,它就不会删除该字段的初始化语句。如果我们使用预期的初始化语句再次添加该字段,它将在原始初始化语句之前执行。因此,service
字段首先分配给MockServiceImpl
,然后分配给null
。请参阅以下javassist错误。
对于问题#2,我不确定为什么会这样。你的javassist版本是什么?你的mockClass看起来怎么样?你能参考下面的javassist bug吗?
Javassist causes java.lang.ClassFormatError: Invalid length 561 in LocalVariableTable in class file