工程背景:
我们的数据在经历BO -> DTO -> VO
的过程经常要进行各种拷贝
之前我们定义了基础的POJO类
/**
* 基础POJO类
* @author
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class AbstractObject {
/**
* 浅度克隆
* @param clazz
* @return
* @throws Exception
*/
public <T> T clone(Class<T> clazz) throws Exception {
T target = clazz.newInstance();
BeanCopierUtils.copyProperties(this, target);
return target;
}
DTO类继承该基础类,调用clone方法即可把属性克隆成DTO类
/**
* 类目DTO类
* @author zhonghuashishan
*
*/
public class CategoryDTO extends AbstractObject {
/**
* id
*/
private Long id;
/**
* 类目名称
*/
private String name;
CategoryDTO category = category.clone(CategoryDO.class);
但是这样还是存在问题,仅仅限于但属性类型的拷贝,
如果属性里有List类型。里面又进一步有嵌套,就不行了。
因此我们需要进一步AbstractObject 进行扩展,实现更加便捷的深度拷贝:
/**
* 基础POJO类
* @author
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class AbstractObject {
/**
* 浅度克隆
* @param clazz
* @return
* @throws Exception
*/
public <T> T clone(Class<T> clazz) throws Exception {
T target = clazz.newInstance();
BeanCopierUtils.copyProperties(this, target);
return target;
}
/**
* 深度克隆
* @param clazz
* @param direction
* @return
* @throws Exception
*/
public <T> T clone(Class<T> clazz, Integer cloneDirection) throws Exception {
// 先完成基本字段的浅克隆
T target = clazz.newInstance();
BeanCopierUtils.copyProperties(this, target);
// 完成所有List类型的深度克隆
Class<?> thisClazz = this.getClass(); // CategoryDTO
Field[] fields = thisClazz.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
// 如果判断某个字段是List类型的
if(field.getType() == List.class) { // field = private List<Relation> relations;
// field.getType() List 不是 List<Relation>
// 获取List集合中的泛型类型
Class<?> listGenericClazz = getListGenericType(field); // RelationDTO
// 获取要克隆的目标类型
Class<?> cloneTargetClazz = getCloneTargetClazz(listGenericClazz, cloneDirection); // 假设CloneDirection是反向,此时获取到的就是RelationVO
// 将list集合克隆到目标list集合中去
List clonedList = new ArrayList();
List<?> list = (List<?>) field.get(this); // List<RelationDTO>集合
cloneList(list, clonedList, cloneTargetClazz, cloneDirection);
// 获取设置克隆好的list的方法名称
Method setFieldMethod = getSetCloneListFieldMethodName(field, clazz); // setRelations
setFieldMethod.invoke(target, clonedList); // target是CategoryVO对象,此时就是调用CategoryVO的setRelations方法,将克隆好的List<CategoryVO>给设置进去
}
}
return target;
}
/**
* 将一个list克隆到另外一个list
* @param sourceList
* @param targetList
* @param cloneTargetClazz
* @param cloneDirection
* @throws Exception
*/
private void cloneList(List sourceList, List targetList,
Class cloneTargetClazz, Integer cloneDirection) throws Exception {
for(Object object : sourceList) {
AbstractObject targetObject = (AbstractObject) object;
AbstractObject clonedObject = (AbstractObject) targetObject.clone(
cloneTargetClazz, cloneDirection); // 将集合中的RelationDTO,调用其clone()方法,将其往RelationVO去克隆
targetList.add(clonedObject); // RelationVO的集合
}
}
/**
* 获取list集合的泛型类型
* @param field
* @return
* @throws Exception
*/
private Class<?> getListGenericType(Field field) throws Exception {
Type genericType = field.getGenericType(); // genericType = List<RelationDTO>,不是List
if(genericType instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) genericType;
return (Class<?>)parameterizedType.getActualTypeArguments()[0];
}
return null;
}
/**
* 获取目标类名
* @param className
* @param cloneDirection
* @return
* @throws Exception
*/
private Class<?> getCloneTargetClazz(Class<?> clazz,
Integer cloneDirection) throws Exception {
String cloneTargetClassName = null;
String className = clazz.getName(); // ReflectionDTO
if(cloneDirection.equals(CloneDirection.FORWARD)) {
if(className.endsWith(DomainType.VO)) {
cloneTargetClassName = className.substring(0, className.length() - 2) + "DTO";
} else if(className.endsWith(DomainType.DTO)) {
cloneTargetClassName = className.substring(0, className.length() - 3) + "DO";
}
}
if(cloneDirection.equals(CloneDirection.OPPOSITE)) {
if(className.endsWith(DomainType.DO)) {
cloneTargetClassName = className.substring(0, className.length() - 2) + "DTO";
} else if(className.endsWith(DomainType.DTO)) {
cloneTargetClassName = className.substring(0, className.length() - 3) + "VO";
}
}
return Class.forName(cloneTargetClassName);
}
/**
* 获取设置克隆好的list的方法名称
* @param className
* @param cloneDirection
* @return
* @throws Exception
*/
private Method getSetCloneListFieldMethodName(Field field, Class<?> clazz) throws Exception {
String name = field.getName();
String setMethodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method setFieldMethod = null;
for(Method method : clazz.getDeclaredMethods()) {
if(method.getName().equals(setMethodName)) {
setFieldMethod = method;
break;
}
}
return setFieldMethod;
}
}
克隆方向定义了从视图层到持久层还是持久层到视图层的拷贝
/**
* 克隆方向
* @author
*
*/
public class CloneDirection {
/**
* 正向克隆:从VO->DTO,DTO->DO
*/
public static final Integer FORWARD = 1;
/**
* 反向克隆:从DO->DTO,DTO->VO
*/
public static final Integer OPPOSITE = 2;
private CloneDirection() {
}
}
深度克隆方法 public T clone(Class clazz, Integer cloneDirection) 能够实现携带List属性的自动拷贝,
前提:
1、List里面也是DTO DO VO
1、类的名称必须是DTO DO VO 结尾的规范名称
使用实例:
来源类
/**
* 类目DTO类
* @author
*
*/
public class CategoryDTO extends AbstractObject {
/**
* id
*/
private Long id;
/**
* 类目名称
*/
private String name;
*/
private List<CategoryPropertyRelationshipDTO> propertyRelations;
目标类
/**
* 类目VO类
* @author
*
*/
public class CategoryVO extends AbstractObject {
/**
* id
*/
private Long id;
/**
* 类目名称
*/
private String name;
/**
* 类目与属性的关联关系
*/
private List<CategoryPropertyRelationshipVO> propertyRelations;
使用:
List propertyRelations; 属性也能得到拷贝
try {
CategoryDTO category = categoryService.getById(id);
CategoryVO resultCategory = category.clone(
CategoryVO.class, CloneDirection.OPPOSITE);
return resultCategory;
} catch (Exception e) {
logger.error("error", e);
return null;
}
- 本文链接: https://blog.zoozer.club/archives/-she-ji-mo-shi-gong-cheng-shi-jian--yuan-xing-mo-shi-de-shen-du-ke-long-shi-xian
- 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!