背景:
有两个相同的class对象source,target。
合并逻辑:用source中!=null的字段覆盖target中为null的字段,对于嵌套的对象需要递归处理。
比如有两个对象:(Student)s1和s2,需要将s2中的内容合并到s1中。
@Data
public Class Person{
private String name;
private Integer age;
}
@Data
public Class Student{
private String schoolAddress;
private Person personInfo;
}
Student s1;
Student s2;
思路:
基于反射去实现这一需求。spring提供了该方法copyProperties
target对象为主体,将source对象的值赋给target。默认是直接覆盖相同字段的全部值,如果不需要处理其中的某些字段,则需要将字段name传入ignoreProperties
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,
@Nullable String... ignoreProperties) throws BeansException
但问题在于是copyProperties只处理当前class的成员,对于内部深层对象不是逐层处理的。
比如:
我想将s1的schoolAddress:"asdfdasdf"和age:12 复制到s2中,对于copyProperties方法来说,只能将s1中的personInfo整体复制过去,而不对内部的age判断进行处理
s1:
{
schoolAddress:"asdfdasdf",
personInfo:{
name:"test1",
age:12
}
}
s1:
{
schoolAddress:null,
personInfo:{
name:"test2",
age:null
}
}
期望的合并结果
{
schoolAddress:"asdfdasdf",
personInfo:{
name:"test2",
age:12
}
}
因此需要我们自己递归实现。
/**
* 将source中内容合并到target中
* 合并逻辑:用source中!=null的字段覆盖target中为null的字段,对于不是枚举,基础类型,包装类,Collection,String的对象进行递归处理
* @param source
* @param target
* @param a
* @param <A>
* @throws BeansException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public static <A> void updateProperties(Object source, Object target, Class<A> a) throws BeansException, InstantiationException, IllegalAccessException {
if (source == null) {
return;
}
if (target==null){
target = a.newInstance();
}
final BeanWrapperImpl targetSrc = new BeanWrapperImpl(target);
java.beans.PropertyDescriptor[] targetPds = targetSrc.getPropertyDescriptors();
final BeanWrapperImpl sourceSrc = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] sourcePds = sourceSrc.getPropertyDescriptors();
// target中不为null的字段不需要处理
Set<String> hasValuePropertyNames = new HashSet<>();
for(java.beans.PropertyDescriptor pd : targetPds) {
Object tarValue = targetSrc.getPropertyValue(pd.getName());
Object sourcValue = sourceSrc.getPropertyValue(pd.getName());
// 如果为枚举,基础类型,包装类,list,String 且不为空则不需要复制,添加到名单中
if (null != tarValue && noNeedRecursiveType(pd.getPropertyType())) {
hasValuePropertyNames.add(pd.getName());
} else if (tarValue==null && noNeedRecursiveType(pd.getPropertyType())){
continue;
} else if (pd.getPropertyType() != Class.class){
// 其余类型对象递归处理
if (tarValue==null){
tarValue = pd.getPropertyType().newInstance();
}
updateProperties(sourcValue, tarValue, pd.getPropertyType());
targetSrc.setPropertyValue(pd.getName(), tarValue);
hasValuePropertyNames.add(pd.getName());
}
}
String[] result = new String[hasValuePropertyNames.size()];
// 调用spring的copyProperties进行复制
copyProperties(source, target, hasValuePropertyNames.toArray(result));
}
public static boolean noNeedRecursiveType(Class clazz){
if (clazz==null){
return true;
}
return ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() || isCollectionField(clazz) || String.class.isAssignableFrom(clazz);
}
private static boolean isCollectionField(Class clazz) {
return Collection.class.isAssignableFrom(clazz);
}
private static boolean isPrimitiveOrWrapper(Class clazz) {
return ClassUtils.isPrimitiveOrWrapper(clazz) || String.class.isAssignableFrom(clazz);
}