Spring 使用 BeanUtils.copyProperties 复制 Java Bean 属性


#Spring#


如果有两个 Java Bean,有多个相同类型和命名的属性,可以使用 Spring 的 BeanUtils.copyProperties 快速将一个 Java Bean 对象的属性复制到另外一个 Java Bean 对象中。

Java Bean (什么是 Java Bean )定义中要求实现序列化接口,BeanUtils.copyProperties 不强制这一条。只要属性有 getter、setter 方法即可。

BeanUtils 类的全路径是:

org.springframework.beans.BeanUtils

属于 spring-beans 项目, gradle 中引入 spring-beans 即可:

compile group: 'org.springframework', name: 'spring-beans', version: '5.0.6.RELEASE'

也可以只引入 spring-context, spring-beans 是它的一个依赖:

compile group: 'org.springframework', name: 'spring-context', version: '5.0.6.RELEASE'

使用示例

定义 3 个 Java Bean

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Address {

    private String city;

    public Address() {
    }

    public Address(String city) {
        this.city = city;
    }

}
import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Person {

    private String name;

    private int age;

    public Person() {

    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

}
import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Student {

    private String name;

    private int age;

    private Address address;

    public Student() {

    }

    public Student(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

}

示例: 从 Person 到 Person

Person person1 = new Person("letian", 18);
System.out.println(person1);

Person person2 = new Person();
BeanUtils.copyProperties(person1, person2);
System.out.println(person2);

运行结果:

Person(name=letian, age=18)
Person(name=letian, age=18)

示例: 从 Person 到 Student

Person person = new Person("letian", 18);
Student student = new Student();
BeanUtils.copyProperties(person, student);
System.out.println(student);

运行结果:

Student(name=letian, age=18, address=null)

Person 比 Student 少了一个 address 属性,所以 Student 的 address 是 null。

示例: 从 Student 到 Person

Student student = new Student("letian", 18, new Address("某城市A"));
Person person = new Person();
BeanUtils.copyProperties(student, person);
System.out.println(person);

运行结果:

Person(name=letian, age=18)

示例: 从 Student 到 Student

上面的示例,其实已经够用了,但我们要注意一下,BeanUtils.copyProperties 是浅复制

Student stu01 = new Student("letian", 18, new Address("某城市A"));
Student stu02 = new Student();

BeanUtils.copyProperties(stu01, stu02);
System.out.println("stu02: " + stu02);

// 修改 stu01 address 属性的 city 值,会导致 stu02 中对应的值也发生变化
stu01.getAddress().setCity("某城市B");
System.out.println("修改后:");
System.out.println("stu01: " + stu01);
System.out.println("stu02: " + stu02);

运行结果:

stu02: Student(name=letian, age=18, address=Address(city=某城市A))
修改后:
stu01: Student(name=letian, age=18, address=Address(city=某城市B))
stu02: Student(name=letian, age=18, address=Address(city=某城市B))

错误的使用示例

没有 setter、getter 方法的类,使用 BeanUtils.copyProperties 是没有效果的。

@ToString
public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
Person person1 = new Person("letian", 18);
System.out.println(person1);
Person person2 = new Person();
BeanUtils.copyProperties(person1, person2);
System.out.println(person2);

运行结果:

Person(name=letian, age=18)
Person(name=null, age=0)

可以看到 person2 的name 和 age 都是默认值,复制没有效果。

类似的,下面的这些用法也是错误的:

// 错误用法
String source = "你好";
String target = "Hi";
BeanUtils.copyProperties(source, target);
System.out.println(target); // Hi
// 错误用法
List<String> source = Arrays.asList("A", "B");
List<String> target = Arrays.asList();

BeanUtils.copyProperties(source, target);
System.out.println(target.size()); // 0

( 本文完 )