spring_“BeanUtils.copyProperties拷贝对象忽略null值“

一、前言:开发中,需要使用BeanUtils.copyProperties进行对象拷贝,但是值为null的需要过滤,忽略拷贝,BeanUtils.copyProperties的构造方法中有一个三个参数的

在这里插入图片描述

传入可变长度的字符串,改字符串就是忽略的字段名
二 、实现方式,基于反射,把源对象的值为null的参数名找出来,返回Array<String?> 数组格式
三、代码(kotlin版本)

object PublicUtils {
    /**
     * 获取所有字段为null的属性名
     * 用于BeanUtils.copyProperties()拷贝属性时,忽略空值
     * @param source
     * @return
     */
    fun getNullPropertyNames(source: Any): Array<String?> {
        val emptyNames=  HashSet<String>()
        val fields: Array<Field> = source.javaClass.declaredFields
        fields.forEach {
            it.isAccessible=true
            val value=it.get(source)
            if(value?.toString().isNullOrBlank()) emptyNames.add(it.name)
        }
        val result = arrayOfNulls<String>(emptyNames.size)
        return emptyNames.toArray(result)
    }
}

<think>好的,我现在需要解决用户在使用SpringBeanUtils.copyProperties方法时,复制后对象属性全为null的问题。首先,用户提到他们遇到了这个问题,而根据提供的引用内容,可能的原因有参数顺序错误、属性名称或类型不匹配、访问权限问题等。我需要逐步分析这些可能性,并给出相应的解决方案。 首先,参数顺序是否正确?根据引用[1],SpringBeanUtils.copyProperties方法的参数顺序是源对象在前,目标对象在后,而Apache Commons的BeanUtils相反。如果用户混淆了这两个库的方法,参数顺序颠倒就会导致复制失败,目标对象属性为null。因此,我需要提醒用户检查是否使用了正确的方法,并确认参数的顺序是否正确。 接下来,属性名称和类型是否匹配。如果源对象和目标对象的属性名称不一致,或者类型无法转换,那么复制时这些属性会被忽略,导致目标属性为null。例如,源对象有属性userName,而目标对象是username,大小写不同会导致无法复制。用户需要检查两个类的属性是否一一对应,包括名称和类型。 然后,访问权限的问题。BeanUtils.copyProperties依赖于getter和setter方法。如果这些方法不是public的,或者不存在,那么复制过程无法访问属性,导致复制失败。需要检查源对象的getter方法和目标对象的setter方法是否存在,并且是public的。 另外,引用[3]提到,SpringBeanUtils在复制时会忽略null,而Apache Commons的BeanUtils不会。如果源对象的某些属性为null,使用Spring的方法时这些属性不会被复制到目标对象,可能导致目标对象原本有的属性被覆盖为null。不过用户的问题是所有属性都为null,这可能更倾向于参数顺序或其他问题。但如果用户确实需要处理null,可能需要使用Apache Commons的BeanUtils并配置选项,或者自定义处理。 还有可能是目标对象本身没有正确初始化。如果目标对象未被实例化,即还是null,那么调用copyProperties时会抛出异常,但用户的问题中是属性全为null,可能目标对象已经实例化,但属性未被正确复制。需要确认目标对象是否已经通过new创建。 此外,其他可能的原因包括静态或final修饰的属性,这些属性无法被复制,或者存在嵌套对象需要深拷贝,而BeanUtils默认是浅拷贝。不过这种情况通常导致部分属性为null,而不是全部。 解决方案方面,首先检查参数顺序是否正确,然后检查属性名称和类型是否匹配,确认getter和setter方法存在且可访问。如果使用SpringBeanUtils并且希望忽略null,可能需要切换到Apache Commons的BeanUtils,并配置相关选项。或者,可以手动复制属性,或使用其他工具如ModelMapper。 例如,引用[3]中的例子展示了如何使用Apache Commons的BeanUtils并设置不忽略null,可能需要注册Converter来处理类型转换。另外,用户需要确保目标对象正确实例化,并且没有其他配置问题。 最后,生成相关问题需要考虑用户可能遇到的类似问题,比如不同工具库的区别、处理嵌套对象、深拷贝与浅拷贝等。</think>### Spring BeanUtils.copyProperties 复制后对象属性全为 null 的解决方案 #### 一、问题原因分析 1. **参数顺序错误** Spring 的 `BeanUtils.copyProperties` 方法参数顺序为**源对象在前,目标对象在后**,而 Apache Commons 的版本参数顺序相反。若混淆两者会导致复制失败[^1]。 ```java // Spring 正确用法 BeanUtils.copyProperties(sourceDemo, targetDemo); // Apache Commons 错误用法(会导致复制失败) BeanUtils.copyProperties(targetDemo, sourceDemo); ``` 2. **属性名称/类型不匹配** 若源对象与目标对象的属性**名称不同**,或**类型无法自动转换**(如 `Date` 转 `String`),属性会被忽略。例如源对象有 `createTime: Date`,而目标对象是 `createTime: String`。 3. **访问权限问题** `BeanUtils.copyProperties` 依赖目标对象的 `setter` 方法和源对象的 `getter` 方法。若方法非 `public` 或不存在,会导致复制失败。 4. **目标对象未初始化** 若目标对象未通过 `new` 实例化,直接调用会抛出空指针异常。例如: ```java TargetDemo target = null; // 错误 BeanUtils.copyProperties(source, target); ``` --- #### 二、解决方案 1. **检查参数顺序与库版本** 确认使用的是 `org.springframework.beans.BeanUtils`,并检查参数顺序是否为 `(源对象, 目标对象)`[^1]。 2. **核对属性映射关系** 通过反射工具检查属性名称和类型是否一致: ```java // 打印源对象属性 Arrays.stream(source.getClass().getDeclaredFields()).forEach(f -> System.out.println(f.getName() + ": " + f.getType())); // 打印目标对象属性 Arrays.stream(target.getClass().getDeclaredFields()).forEach(f -> System.out.println(f.getName() + ": " + f.getType())); ``` 3. **显式声明 getter/setter 方法** 确保所有需要复制的属性都有 `public` 的访问方法: ```java // 源对象 public class SourceDemo { private String name; public String getName() { return name; } // 必须存在 } // 目标对象 public class TargetDemo { private String name; public void setName(String name) { this.name = name; } // 必须存在 } ``` 4. **处理 null 问题** 若需要保留目标对象原有(仅覆盖非 null 属性),使用 Apache Commons 的 `BeanUtils` 并配置忽略 null: ```java // 配置忽略 null BeanUtilsBean utils = new BeanUtilsBean() { @Override public void copyProperty(Object dest, String name, Object value) throws IllegalAccessException, InvocationTargetException { if (value != null) { super.copyProperty(dest, name, value); } } }; utils.copyProperties(targetDemo, sourceDemo); // Apache Commons 参数顺序 ``` --- #### 三、替代方案 | 工具 | 特点 | 示例代码 | |---------------------|-----------------------------------|-----------------------------------| | **MapStruct** | 编译时生成代码,性能最佳 | `Mapper.INSTANCE.toDto(source)` | | **ModelMapper** | 支持复杂映射规则 | `modelMapper.map(source, Target.class)` | | **手动复制** | 完全可控,适合少量属性 | `target.setName(source.getName())` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值