如何优雅的合并两个对象

提出需求

相信很多时候,你可能有这样的需求,比如A对象的属性1、属性2是你需要的,其余属性是空值,而B对象的属性3、属性4是你需要的,其余属性是空值,那么如何将A对象的属性与B对象的属性结合呢?

思路解析

要实现将两个对象的属性结合,需要用到反射技术,遍历每个对象的属性,将非null的属性复制给null的属性,最后实现合并属性的效果。

常用的复制对象属性的方法(传统方案)

使用Java Bean Utils,这是Apache Commons BeanUtils库中的一个工具类,使用此工具类,则需要自己去实现判断属性的业务逻辑。

这个工具类有两个复制属性的方法,copyProperties和copyProperty。

static void copyProperties(Object dest, Object orig)Copy property values from the origin bean to the destination bean for all cases where the property names are the same.
static void copyProperty(Object bean, String name, Object value)Copy the specified property value to the specified destination bean, performing any type conversion that is required.

copyProperties方法会将orig(第二个对象)的属性复制给dest(第二个对象),这种复制是完全复制,会完全覆盖dest的属性。

copyProperty方法将复制value给bean的特定属性。

hutool合并对象的方案

Hutool是一个Java工具包类库,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类。

hutool常常被广大spring程序员唾弃,抱怨其在项目中的稳定性,bug问题。但我认为,hutool是一个在不断迭代和维护的库,虽然是国内程序员开发的,但是其中很多功能仍然是简单好用的,不能够以偏概全的全面否定它。

回归正题,下面做详细的说明

pom导入合并对象所必须的hutool库

xml 复制代码
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-core</artifactId>
    <version>5.8.16</version>
</dependency>

方法解释

  • cn.hutool.core.bean.BeanUtil
static <T> T copyProperties(Object source, Class<T> tClass, String... ignoreProperties)按照Bean对象属性创建对应的Class对象,并忽略某些属性
static void copyProperties(Object source, Object target, boolean ignoreCase)复制Bean对象属性
static void copyProperties(Object source, Object target, CopyOptions copyOptions)复制Bean对象属性 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类
static void copyProperties(Object source, Object target, String... ignoreProperties)复制Bean对象属性 限制类用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类

hutool的复制对象方法copyProperties有4个重载类型,在apache common beanutils的基础上,增加了一些复制选项,这些选项是非常实用的,比如忽略大小写、忽略某些属性、某些特定的复制选项等。

copyProperties(Object source, Object target, CopyOptions copyOptions)

因为我实际用了copyProperties(Object source, Object target, CopyOptions copyOptions),重点讲解此方法的传入参数。

CopyOptions包括以下的一些属性或选项,可以根据你的项目需求来选择

限定符和类型 字段和说明
protected TypeConverter converter自定义类型转换器,默认使用全局万能转换器转换
protected Class<?> editable限制的类或接口,必须为目标对象的实现接口或父类,用于限制拷贝的属性,例如一个类我只想复制其父类的一些属性,就可以将editable设置为父类 如果目标对象是Map,源对象是Bean,则作用于源对象上
protected BiFunction<String,Object,Object> fieldValueEditor字段属性值编辑器,用于自定义属性值转换规则,例如null转""等
protected boolean ignoreCase是否忽略字段大小写
protected boolean ignoreError是否忽略字段注入错误
protected boolean ignoreNullValue是否忽略空值,当源对象的值为null时,true: 忽略而不注入此值,false: 注入null
protected boolean override是否覆盖目标值,如果不覆盖,会先读取目标对象的值,非null则写,否则忽略。
protected boolean transientSupport是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。

自己写的合并工具类

该工具类仅供参考,可以根据自己情况调整

java 复制代码
public class MergeUtil {
    private static final CopyOptions options = CopyOptions.create().setIgnoreNullValue(true).setOverride(false);
    private static final CopyOptions optionsAllowOverride = CopyOptions.create().setIgnoreNullValue(true).setOverride(true);

    //将tagetBean中的属性合并到sourceBean,忽略Null值,非Null值不允许覆盖
    public static Object merge(Object sourceBean, Object targetBean) {
        BeanUtil.copyProperties(sourceBean, targetBean, options);

        return targetBean;
    }

    //将tagetBean中的属性合并到sourceBean,忽略Null值,非Null值允许覆盖
    public static Object mergeAllowOverride(Object sourceBean, Object targetBean) {
        BeanUtil.copyProperties(sourceBean, targetBean, optionsAllowOverride);

        return targetBean;
    }
}
相关推荐
学长毕业设计5 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
东小西5 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西5 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午6 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065256 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
阿kun要赚马内6 小时前
MySQL 索引基础
后端·mysql
小范同学_6 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
码事漫谈6 小时前
我啥都能做,却不知道做什么了
后端
geovindu7 小时前
CSharp: 万年历
开发语言·后端·c#·.net
予昊7 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket