java Spring BeanUtils 使用 List 字段复制属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42469618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring BeanUtils copy properties with a field of List
提问by cgon
I hava Foo and Item class as below.
我有 Foo 和 Item 类,如下所示。
import java.util.ArrayList;
import java.util.List;
public class Foo {
private Long id;
private List<Item> items;
public Foo(Long id) {
this.id = id;
this.items = new ArrayList<Item>();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
public class Item {
private String bar;
public Item(String bar) {
this.bar = bar;
}
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
@Override
public String toString() {
return "Item{" + "bar='" + bar + '\'' + '}';
}
}
When I am copying the Foo class using spring BeanUtils the reference for the list field is not changing.
当我使用 spring BeanUtils 复制 Foo 类时,列表字段的引用没有改变。
import org.springframework.beans.BeanUtils;
public class SimpleCopyMain {
public static void main(String[] args) {
Foo foo = new Foo(1L);
foo.getItems().add(new Item("item1"));
foo.getItems().add(new Item("item2"));
Foo fooSnapShot = new Foo(100L);
BeanUtils.copyProperties(foo,fooSnapShot);
foo.setId(999L);
System.out.println("fooSnapShot id field value is not changing as expected : " + fooSnapShot.getId());
foo.getItems().add(new Item("item3"));
System.out.println("fooSnapShot items value is changing unexpectedly : " + fooSnapShot.getItems());
}
}
The output for SimpleCopyMain class is below :
SimpleCopyMain 类的输出如下:
fooSnapShot id field value is not changing as expected : 1
fooSnapShot items value is changing unexpectedly : [Item{bar='item1'}, Item{bar='item2'}, Item{bar='item3'}]
However when I create a new instance for the list field and copy the references one by one, I get the behaviour as I expected.
但是,当我为列表字段创建一个新实例并一一复制引用时,我得到了预期的行为。
import java.util.ArrayList;
import org.springframework.beans.BeanUtils;
public class CopyMain {
public static void main(String[] args) {
Foo foo = new Foo(1L);
foo.getItems().add(new Item("item1"));
foo.getItems().add(new Item("item2"));
Foo fooSnapShot = new Foo(100L);
BeanUtils.copyProperties(foo, fooSnapShot);
fooSnapShot.setItems(new ArrayList<Item>(foo.getItems().size()));
for(int i = 0; i < foo.getItems().size(); i++){
Item anItem = new Item("");
BeanUtils.copyProperties(foo.getItems().get(i), anItem);
fooSnapShot.getItems().add(anItem);
}
foo.setId(999L);
System.out.println("fooSnapShot id field value is not changing as expected : " + fooSnapShot.getId());
foo.getItems().add(new Item("item3"));
System.out.println("fooSnapShot items value is is not changing : " + fooSnapShot.getItems());
}
}
Here is the output :
这是输出:
fooSnapShot id field value is not changing as expected : 1
fooSnapShot items value is is not changing : [Item{bar='item1'}, Item{bar='item2'}]
And my pom :
还有我的 pom :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.question</groupId>
<artifactId>beanutils</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
</dependencies>
</project>
Why is the spring beanutils not clone a list field ?
为什么 spring beanutils 不克隆列表字段?
回答by hya
According to BeanUtil copyProperities method implementation, Spring is copying your data via Getters and Setters. If you have primitives like Integer it's ok, but for your List field, you are passing reference in Setter.
根据 BeanUtil copyProperities 方法实现,Spring 正在通过 Getter 和 Setter 复制您的数据。如果你有像 Integer 这样的原语,那没关系,但是对于你的 List 字段,你是在 Setter 中传递引用。
If you'd like it to work, you need to change your setter to:
如果你想让它工作,你需要将你的 setter 更改为:
public void setItems(List<Item> items) {
this.items = new ArrayList<>(items);
}
This will do also shallow copy, but you won't have list reference.
这也将进行浅拷贝,但您将没有列表引用。
回答by artemisian
If you look at the spring's BeanUtils.copyProperties you can see that all is doing is performing a shallow copy of the properties meaning only properties with primitive values will be cloned, all other properties will copied by reference. Behind the scenes Spring is using PropertyDescriptor and calling the getter on the source property and calling the setter in the target property.
如果您查看 spring 的 BeanUtils.copyProperties,您会发现所做的只是执行属性的浅拷贝,这意味着只有具有原始值的属性才会被克隆,所有其他属性都将通过引用进行复制。在幕后,Spring 正在使用 PropertyDescriptor 并在源属性上调用 getter 并在目标属性中调用 setter。
So when you call BeanUtils.copyProperties(foo, fooSnapShot);
at that moment foo and fooSnapShot share the same reference to the items list, and that's why the list can be changed through the foo or fooSnapshot instances, however, in your second case you are giving fooSnapShot a reference to a different List fooSnapShot.setItems(new ArrayList<Item>(foo.getItems().size()));
and that's why you get your expected results.
因此,当您BeanUtils.copyProperties(foo, fooSnapShot);
在那一刻调用foo 和 fooSnapShot 共享对项目列表的相同引用时,这就是为什么可以通过 foo 或 fooSnapshot 实例更改列表的原因,但是,在第二种情况下,您将给 fooSnapShot 一个对不同列表的引用fooSnapShot.setItems(new ArrayList<Item>(foo.getItems().size()));
这就是您获得预期结果的原因。