有几种工具可以实现“非空复制“(只复制源对象中非空的值到目标对象)
有几种工具可以实现"非空复制"(只复制源对象中非空的值到目标对象):
1. Spring BeanUtils + 自定义工具类(推荐)
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.util.HashSet;
import java.util.Set;public class BeanCopyUtil {/*** 只复制非null属性*/public static void copyNonNullProperties(Object source, Object target) {BeanUtils.copyProperties(source, target, getNullPropertyNames(source));}/*** 获取为null的属性名数组*/private static String[] getNullPropertyNames(Object source) {final BeanWrapper src = new BeanWrapperImpl(source);java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();Set<String> emptyNames = new HashSet<>();for (java.beans.PropertyDescriptor pd : pds) {Object srcValue = src.getPropertyValue(pd.getName());if (srcValue == null) {emptyNames.add(pd.getName());}}return emptyNames.toArray(new String[0]);}
}// 使用示例
SourceBean source = new SourceBean();
source.setName("张三"); // 有值
// source.setAge(null); // 没设置值TargetBean target = new TargetBean();
target.setAge(25); // 目标对象原有值BeanCopyUtil.copyNonNullProperties(source, target);
// 结果:target的name变为"张三",age仍为25(不会被覆盖为null)2. Hutool工具库(国产优秀工具)
// 添加依赖
// implementation 'cn.hutool:hutool-all:5.8.16'import cn.hutool.core.bean.BeanUtil;SourceBean source = new SourceBean();
source.setName("张三");TargetBean target = new TargetBean();
target.setAge(25);// 只复制非null值
BeanUtil.copyProperties(source, target, CopyOptions.create().setIgnoreNullValue(true) // 忽略null值.setIgnoreError(true)); // 忽略错误// 或者使用CopyOptions的快捷方式
BeanUtil.copyProperties(source, target, true, true);3. MapStruct配置非空复制
@Mapper
public interface BeanMapper {BeanMapper INSTANCE = Mappers.getMapper(BeanMapper.class);@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)void updateTargetFromSource(SourceBean source, @MappingTarget TargetBean target);
}// 使用
SourceBean source = new SourceBean();
source.setName("张三");TargetBean target = new TargetBean();
target.setAge(25);BeanMapper.INSTANCE.updateTargetFromSource(source, target);4. Apache Commons BeanUtils3(新版)
// 使用BeanUtilsBean2
import org.apache.commons.beanutils3.BeanUtilsBean;SourceBean source = new SourceBean();
source.setName("张三");TargetBean target = new TargetBean();
target.setAge(25);BeanUtilsBean.getInstance().copyProperties(target, source);
// 注意:新版默认可能忽略null,老版本需要自定义5. 自定义通用工具类(增强版)
public class BeanCopyUtils {/*** 智能复制:只复制非null属性,支持字段名映射*/public static <S, T> void smartCopyProperties(S source, T target, Map<String, String> fieldMapping) {if (source == null || target == null) return;BeanWrapper srcWrapper = new BeanWrapperImpl(source);BeanWrapper tarWrapper = new BeanWrapperImpl(target);// 获取源对象所有属性PropertyDescriptor[] srcPds = srcWrapper.getPropertyDescriptors();for (PropertyDescriptor srcPd : srcPds) {String srcFieldName = srcPd.getName();// 跳过class属性if ("class".equals(srcFieldName)) continue;// 获取目标字段名(支持映射)String tarFieldName = fieldMapping.getOrDefault(srcFieldName, srcFieldName);if (tarWrapper.isWritableProperty(tarFieldName)) {Object value = srcWrapper.getPropertyValue(srcFieldName);// 只复制非null值if (value != null) {tarWrapper.setPropertyValue(tarFieldName, value);}}}}// 简化版本(不需要字段映射)public static <S, T> void smartCopyProperties(S source, T target) {smartCopyProperties(source, target, new HashMap<>());}
}// 使用示例
SourceBean source = new SourceBean();
source.setName("张三");TargetBean target = new TargetBean();
target.setAge(25);// 简单使用
BeanCopyUtils.smartCopyProperties(source, target);// 带字段映射
Map<String, String> mapping = new HashMap<>();
mapping.put("userName", "name"); // 源userName映射到目标name
BeanCopyUtils.smartCopyProperties(source, target, mapping);推荐方案
根据项目情况选择:
Spring项目:使用方案1(Spring BeanUtils + 自定义工具类)
需要高性能:使用方案3(MapStruct)
工具类丰富项目:使用方案2(Hutool)
简单需求:使用方案5的自定义工具类
最常用的是方案1,因为它依赖Spring框架,大多数项目都在使用,且性能良好。
