字节码技术:解决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(); } }