Spring中的BeanUtils.copyProperties踩坑记录

BeanUtils.copyProperties() 是 Spring 框架中的一个工具方法,用于将一个 JavaBean 对象的属性值复制到另一个 JavaBean 对象中。其作用是将源对象的属性值复制到目标对象中,从而实现对象属性的拷贝。下面详细解释其作用和原理:

作用:

  1. 属性拷贝:将一个对象的属性值复制到另一个对象中,通常用于 DTO(数据传输对象)和领域模型对象之间的属性拷贝,以便在它们之间进行数据传输和转换。
  2. 简化代码:避免了手动逐个设置属性值的繁琐过程,提高了代码的简洁性和可读性。
  3. 类型转换:在属性值拷贝过程中,BeanUtils 可以自动进行类型转换,使得源对象和目标对象的属性类型不必完全一致。

原理:

  1. 反射:BeanUtils.copyProperties() 方法通过 Java 的反射机制来实现属性值的复制。它会获取源对象和目标对象的所有属性,并逐一进行复制。
  2. 属性名匹配:方法会通过反射机制获取源对象和目标对象的所有属性,并且会根据属性名进行匹配。只有在源对象和目标对象中具有相同名称且可访问的属性时,才会进行属性复制。
  3. 属性赋值:对于匹配的属性,会将源对象中的属性值直接赋值给目标对象的对应属性。这里的赋值操作是直接的引用赋值,不会进行类型转换或者复制属性值所引用的对象。
  4. 类型兼容性:如果源对象的属性类型与目标对象的属性类型不兼容,例如源对象的属性是基本类型,而目标对象的属性是包装类型,或者两者的属性类型不同,那么在赋值过程中会抛出类型转换异常。
  5. 属性过滤:可以通过设置参数来指定要复制的属性列表,从而实现部分属性的复制。

因此,在使用 BeanUtils.copyProperties() 方法时,需要注意确保源对象和目标对象的属性类型和名称都匹配,以避免类型转换异常或属性复制不完整的情况发生。对于类型不匹配的属性,需要提前进行类型转换或者采取其他适当的处理方式。

是浅拷贝还是深拷贝?

BeanUtils.copyProperties() 方法实现的是浅拷贝。

在浅拷贝中,只复制对象的引用,而不复制引用指向的对象。这意味着,如果源对象和目标对象的属性是对象类型(非基本数据类型),则它们在内存中引用的是同一个对象,而不是两个相互独立的对象。因此,如果修改了其中一个对象的属性,另一个对象的相应属性也会受到影响。

举例来说,假设源对象 source 和目标对象 target 都有一个属性 list,它们都引用同一个 ArrayList 对象。当使用 BeanUtils.copyProperties() 方法进行属性复制时,只会复制 list 属性的引用,而不会复制 ArrayList 对象本身。因此,如果修改了 source 对象的 list 属性,target 对象的 list 属性也会发生变化,因为它们引用的是同一个 ArrayList 对象。

如果需要进行深拷贝,即复制对象及其所有属性的副本,可以考虑使用其他工具或手动实现深拷贝逻辑,例如使用第三方库(如 Apache Commons BeanUtils 中的 BeanUtils.cloneBean() 方法)或手动递归复制对象的所有属性。

踩坑记录

1.属性名称和类型匹配问题

源对象和目标对象的属性名称要完全匹配,否则会导致部分属性无法复制或者属性值错误。另外,属性的类型也要保持一致,否则可能会发生类型转换异常。

2.深拷贝问题

BeanUtils.copyProperties() 方法进行的是浅拷贝,如果源对象的属性值是对象类型,并且被多个对象引用,那么目标对象的相应属性值也会引用同一个对象。这可能导致在修改一个对象的属性值时,其他对象的属性值也会受到影响。

java 复制代码
//源对象
@Data  
public class SourceObject {  
private String name;  
private int age;  
private Map<String,String> map;  
}

//目标对象
@Data  
public class TargetObject {  
private String name;  
private int age;  
private Map<String,String> map;  
}

这时目标对象确实赋值了。但是如果改变map对象,目标对象也会跟着改变。

3.null 值处理

默认情况下,BeanUtils.copyProperties() 方法会将源对象中的所有非 null 属性值复制到目标对象中。如果希望忽略源对象中的 null 属性值,可以使用 BeanUtils.copyProperties() 方法的重载版本,并设置 ignoreNullSource 参数为 true

4.bean对应的属性,没有getter和setter方法

BeanUtils.copyProperties要拷贝属性值成功,需要对应的bean要有getter和setter方法。因为它是用反射拿到set和get方法再去拿属性值和设置属性值的。

5.属性是泛型,不会赋值

推荐使用hutool工具包的BeanUtil.copyProperties()

xml 复制代码
<!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.17</version>
        </dependency>

注意以下几点:

  1. 属性名和数据类型必须匹配

    • 在源对象和目标对象之间进行属性拷贝时,属性名和数据类型必须保持一致。如果属性名或数据类型不匹配,可能会导致拷贝失败或异常。
    • 只有在目标对象已经存在对应的属性时,才会进行属性值的复制。
  2. 自动属性映射

    • 如果源对象和目标对象的属性名不一致,但是数据类型匹配,BeanUtil.copyProperties() 方法会自动进行属性映射,将源对象的属性值复制到目标对象对应的属性中。

    • 1.属性名匹配: 如果源对象和目标对象的属性名完全一致,则直接进行属性值的复制。

    • 2.驼峰命名转换:如果源对象和目标对象的属性名不完全一致,但是符合驼峰命名规范(例如:sourceName 和 targetName),则会尝试进行驼峰命名的转换。例如,将 sourceName 转换为 source_name,然后与目标对象的属性进行匹配。

    • 3.忽略大小写:属性映射时会忽略属性名的大小写。即使源对象和目标对象的属性名在大小写上有差异,也会尝试进行匹配。

  3. 支持嵌套对象的属性复制

    • BeanUtil.copyProperties() 方法支持嵌套对象的属性复制,即如果源对象和目标对象的属性包含其他对象类型的属性,也会递归地进行属性复制。
  4. 支持集合属性的复制

    • Hutool 的 BeanUtil.copyProperties() 方法支持集合属性的复制,即如果源对象和目标对象的属性包含集合类型(如 List、Set、Map 等)的属性,也会进行正确的复制。
  5. 处理 null 值

    • 默认情况下,如果源对象的属性值为 null,BeanUtil.copyProperties() 方法不会将该属性复制到目标对象中,目标对象的属性值保持不变。这种行为可以避免将 null 值赋给目标对象的属性。
  6. 属性是泛型,不会赋值

相关推荐
今天背单词了吗98016 分钟前
算法学习笔记:8.Bellman-Ford 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·开发语言·后端·算法·最短路径问题
天天摸鱼的java工程师19 分钟前
使用 Spring Boot 整合高德地图实现路线规划功能
java·后端
东阳马生架构34 分钟前
订单初版—2.生单链路中的技术问题说明文档
java
咖啡啡不加糖1 小时前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南1 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
DKPT1 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
Percep_gan1 小时前
idea的使用小技巧,个人向
java·ide·intellij-idea
缘来是庄1 小时前
设计模式之迭代器模式
java·设计模式·迭代器模式
Liudef061 小时前
基于HTML与Java的简易在线会议系统实现
java·前端·html
JosieBook1 小时前
【Java编程动手学】Java常用工具类
java·python·mysql