加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

如何使用javassist更改字段的初始值

发布时间:2020-12-14 06:08:38 所属栏目:Java 来源:网络整理
导读:我正试图在我的开发环境中模拟一些服务. serviceFactory代码类似于: public class ApiFacadeImpl implements ApiFacade {private OneService oneService = null; public OneService getOneService(){ if(oneService==null) {//some initialization steps }

我正试图在我的开发环境中模拟一些服务. 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;
    }

非常感谢.

最佳答案
对于问题#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();

我尝试了你提出的方式.但是,它没有用.经过一些调试后,我发现如果我们删除一个字段,它就不会删除该字段的初始化语句.如果我们使用预期的初始化语句再次添加该字段,它将在原始初始化语句之前执行.因此,服务字段首先分配给MockServiceImpl,然后分配给null.请参阅以下javassist错误.

javassist-3.14.0-GA – Problm in default initializer of class variables when they are deleted and created using removeField and addField,CtField.make

对于问题#2,我不确定为什么会发生这种情况.你的javassist版本是什么?你的mockClass看起来怎么样?你能参考下面的javassist bug吗?

Javassist causes java.lang.ClassFormatError: Invalid length 561 in LocalVariableTable in class file

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读