最近项目有个需求,需要在全部实体上增加一个字段,并使用统一方法调用,就试着用javassist实现。
1、引入jar包
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.26.0-GA</version>
</dependency>
2、新增方法
private T enhanceEntity(T old,String deleteUser) throws NotFoundException, CannotCompileException,
ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String addFieldName = "deleteUser";
boolean enhance = false;
//增强实体类
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(old.getClass().getName());
CtField[] fields = ctClass.getDeclaredFields();
for(CtField field : fields){
if(addFieldName.equals(field.getName())){
enhance = true;
break;
}
}
if(!enhance){
//如果类被冻结,解冻
if(ctClass.isFrozen()){
ctClass.defrost();
}
//增加新字段
CtField ctField = new CtField(pool.get(String.class.getName()), addFieldName, ctClass);
ctField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ctField);
}
//同个Class不能在同个ClassLoader中加载两次,所以需要使用javassist提供的ClassLoader
Loader classLoader = new Loader(pool);
// 生成新的字节码
Class<?> newClass = classLoader.loadClass(ctClass.getName());
// 用新的字节码创建新的对象
Object newObject = newClass.newInstance();
// 设置原有属性的值
for (Field oldField: old.getClass().getDeclaredFields()) {
// 跳过final属性,因为final属性无法修改
if (java.lang.reflect.Modifier.isFinal(oldField.getModifiers())) {
continue;
}
oldField.setAccessible(true);
Field newField = newClass.getDeclaredField(oldField.getName());
newField.setAccessible(true);
newField.set(newObject, oldField.get(old));
}
Field field = newClass.getDeclaredField(addFieldName);
field.setAccessible(true);
field.set(newObject, deleteUser);
return (T)newObject;
}
经过简单测试,可以实现需求,如果有缺陷或者问题,后续会继续跟进修改维护