字节码技术:解决mybatis返回对象新增变量问题-javassist

根据枚举类型进行数据统计,当枚举类型有改动时,统计输出也需要动态改动。这时数据相关的对象变量和方法都需要改动,很不方便、

 通过字节码技术,在类加载时生成对象类型:

TestVo.java

//对象class中没有变量, 只有公共的getType\setType方法,对外提供便利的数据读取和设置方式。

public class TestVo {

     // set方法供外部直观调用
    public void setType(int  type,int value){
        String mname = "set_type_" + alarm_type;
         try {
            Method method = this.getClass().getMethod(mname,int.class);
            if(method == null ){
                return   ;
            }
            method.invoke(this, value);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    //get方法
    public int getType(int type){
        try {
            String mname = "get_type_" + type;
            Method method = this.getClass().getMethod(mname); // 需要与枚举类方法对应
            if(method == null ){
                return 0 ;
            }
            Object invoke = method.invoke(this, null);
            return Integer.valueOf(invoke.toString());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return 0 ;
    }

}

 

//系统启动时,动态修改类资源字节码,添加变量、get\set方法,然后加载对象class。

//字节码对类的变量和方法进行处理
public static void init () {
    try {
        AlarmTypeEnum[] enums =  AlarmTypeEnum.values() ;
        ClassPool cp = ClassPool.getDefault();
        //添加项目资源路径,要不然找不到类 javassist.NotFoundException:
        cp.insertClassPath(new ClassClassPath(AA.class ));
        //类加载器加载一次,反射重复加载了同一个类会报错,这里直接采用路径  ,使用 AlarmTrendStatisticsVo.class.getName() 已经被加载 ,toclass会报错
        CtClass cc = cp.get("com.**.TestVo"  );
        CtField[] fields = cc.getDeclaredFields();
        List<String > list = Arrays.stream(fields).map(CtField::getName).collect(Collectors.toList());
        for(TypeEnum typeEnum: enums) {
            int type = typeEnum.getCode();
            String fieldName   = "type_" + type;
            if(!list.contains(fieldName)){
                //添加一个int类型的共有属性
                CtField fieldId = new CtField(CtClass.intType, fieldName, cc);
                fieldId.setModifiers(AccessFlag.PUBLIC);
                cc.addField(fieldId);
                // 添加get方法
                CtMethod get = CtNewMethod
                        .make("public int get"+ StringUtil.upperCase(fieldName)  +"( ){ return "+fieldName+";}", cc);
                cc.addMethod(get);
                // 添加set方法
                CtMethod set = CtNewMethod
                        .make("public void set"+ StringUtil.upperCase(fieldName) +"( int  i  ){  this."+fieldName +" = i ;}", cc);
                cc.addMethod(set);
            }
        }
        cc.toClass();
        // 释放对象
        cc.detach();
    }catch ( Exception e){
        e.printStackTrace();
    }
}

  


posted @ 2023-02-06 11:43  higsan  阅读(70)  评论(0编辑  收藏  举报