Why is it not recommended to use BeanUtils.copyProperties to copy data?

In actual business development, we often encounter assignments between object attributes such as VO, BO, PO, DTO, etc. When there are many attributes, the workload of assigning values ​​using get and set methods is relatively large, so the workload is relatively large. Many people will choose to use the copyProperties method of BeanUtils, a copy tool provided by spring, to copy properties between objects. This method can greatly reduce our workload of manually writing object attribute assignment code. Since it is so convenient, why is it not recommended? Below are some common pitfalls in BeanUtils.copyProperties data copying that I compiled .

1: Inconsistent attribute types cause copy failure

This pit can be subdivided into the following two types:
(1) The same attribute has different types
In actual development, it is very likely that the same field has inconsistent types defined in different classes. For example, ID may be defined in class A as Long and in class B as String. In this case, if you use BeanUtils When copying .copyProperties , the copy will fail, causing the corresponding field to be null. The corresponding cases are as follows:
  
  
  
  
  
public class BeanUtilsTest {
public static void main(String[] args) { SourcePoJo sourcePoJo = new SourcePoJo("jingdong", (long) 35711); TargetPoJo targetPoJo = new TargetPoJo(); BeanUtils.copyProperties(sourcePoJo,targetPoJo); System.out.println(targetPoJo); }}@Data@AllArgsConstructorclass SourcePoJo{ private String username; private Long id;}
@Dataclass TargetPoJo{ private String username; private String id;}
The corresponding running results are as follows:
You can see that the copied value of the id field is null due to inconsistent types.
(2) The same field uses packaging type and basic type respectively
If you use a wrapper class and a basic type respectively for a field, an exception will occur when no actual value is passed. The specific cases are as follows:
  
  
  
  
  
public class BeanUtilsTest {
public static void main(String[] args) { SourcePoJo sourcePoJo = new SourcePoJo(); sourcePoJo.setUsername("joy"); TargetPoJo targetPoJo = new TargetPoJo(); BeanUtils.copyProperties(sourcePoJo,targetPoJo); System.out.println(targetPoJo); }}@Dataclass SourcePoJo{ private String username; private Long id;}
@Dataclass TargetPoJo{ private String username; private long id;}
In the test case, the id field uses the wrapper type and basic type in the copy source and copy target respectively. You can see that an exception occurred during copying.

Note: If a Boolean type attribute uses a basic type and a wrapper type respectively, and if the attribute name starts with is, such as isSuccess, it will also cause the copy to fail.

2: Null value overwriting causes data anomalies

During business development, we may have the need to copy some fields . If some fields in the copied data have null values, but the values ​​of the same fields in the corresponding data that need to be copied are not null, if directly When BeanUtils.copyProperties is used to copy data, the null value of the copied data will overwrite the fields of the copy target data, causing the original data to become invalid.
The corresponding cases are as follows:
  
  
  
  
  
public class BeanUtilsTest {
public static void main(String[] args) { SourcePoJo sourcePoJo = new SourcePoJo(); sourcePoJo.setId("35711"); TargetPoJo targetPoJo = new TargetPoJo(); targetPoJo.setUsername("Joy"); BeanUtils.copyProperties(sourcePoJo,targetPoJo); System.out.println(targetPoJo); }}@Dataclass SourcePoJo{ private String username; private String id;}
@Dataclass TargetPoJo{ private String username; private String id;}
The corresponding running results are as follows:

You can see that the username field that originally had a value in the copy target result has been overwritten to null. Although you can use the overloaded method of BeanUtils.copyProperties and use the custom ConvertUtilsBean to copy some fields, doing so itself is more complicated and loses the meaning of using BeanUtils.copyProperties to copy data, so it is not recommended. .

3: Package import error leads to abnormal copy data

When using BeanUtils.copyProperties to copy data, if both Spring's beans package and Apache's beanutils package are introduced into the project, if there is an import error when importing the package, it is likely to cause the data copy to fail, which is not easy to detect during troubleshooting. We usually use the copy method in the Sping package. The differences between the two are as follows:
  
  
  
  
  
//org.springframework.beans.BeanUtils(源对象在左边,目标对象在右边)public static void copyProperties(Object source, Object target) throws BeansException //org.apache.commons.beanutils.BeanUtils(源对象在右边,目标对象在左边)public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException

4: The field reference cannot be found, and the modified content is difficult to trace.

During development or troubleshooting, if we find the source of a field value ( not passed by the caller ) in the link, we may use full-text search to find its corresponding assignment method (such as set method, build method, etc.), but if the data is copied using BeanUtils.copyProperties in the link , it will be difficult to quickly locate the place where the value is assigned, resulting in low troubleshooting efficiency.

5: Internal class data cannot be copied successfully

Internal class data cannot be copied normally, even if the type and field name are the same, the copy cannot be successful, as shown below:
  
  
  
  
  
public class BeanUtilsTest {
public static void main(String[] args) { SourcePoJo sourcePoJo = new SourcePoJo(); sourcePoJo.setUsername("joy"); SourcePoJo.InnerClass innerClass = new SourcePoJo.InnerClass("sourceInner"); sourcePoJo.innerClass=innerClass; System.out.println(sourcePoJo.toString()); TargetPoJo targetPoJo = new TargetPoJo(); BeanUtils.copyProperties(sourcePoJo,targetPoJo); System.out.println(targetPoJo.toString()); }}//下面是类的信息,这里就直接放到一块展示了@Data@ToStringpublic class SourcePoJo{ private String username; private Long id; public InnerClass innerClass; @Data @ToString @AllArgsConstructor public static class InnerClass{ public String innerName; }}
@Data@ToStringpublic class TargetPoJo{ private String username; private Long id; public InnerClass innerClass; @Data @ToString public static class InnerClass{ public String innerName; }}
Here are the results:

In the above case, there is an inner class InnerClass in the copy source and copy target. Although the inner class attributes are the same and the class name is the same, they are in different classes, so Spring will think that the attributes are different and will not copy the data. .

6: BeanUtils.copyProperties is a shallow copy

Here I will first review deep copy and shallow copy for everyone.
Shallow copy means creating a new object that has the same property values ​​as the original object but still shares the same reference for properties of reference types. That is to say, under shallow copy, when the reference attribute value of the original content changes, the reference attribute value of the copied object will also change accordingly.
A deep copy means creating a new object with the same property values ​​as the original object, including properties of reference types. Deep copy will recursively copy the reference object and create a brand new object, so the copied object is completely independent from the original object.
The following is the corresponding code example:
  
  
  
  
  
public class BeanUtilsTest {
public static void main(String[] args) { Person sourcePerson = new Person("sunyangwei",new Card("123456")); Person targetPerson = new Person(); BeanUtils.copyProperties(sourcePerson, targetPerson); sourcePerson.getCard().setNum("35711"); System.out.println(targetPerson); }}

@Data@AllArgsConstructorclass Card { private String num;}
@NoArgsConstructor@AllArgsConstructor@Dataclass Person { private String name; private Card card;}
Here are the results:
Summary: From the code running results, we can find that once you modify the reference type data of the original object after copying, it will cause the value of the copied data to be abnormal. This kind of problem is also difficult to troubleshoot.

7: The underlying implementation is reflective copy with low efficiency

The bottom layer of BeanUtils.copyProperties is to obtain the set and get methods of the object through reflection, and then complete the copy of the data through get and set. The overall copy efficiency is low.
The following is a comparison of the efficiency of copying data using BeanUtils.copyProperties and directly setting the value. In order to visually see the effect, here is an example of copying 10,000 times:
  
  
  
  
  
public class BeanUtilsTest {
public static void main(String[] args) { long copyStartTime = System.currentTimeMillis(); User sourceUser = new User("sunyangwei"); User targetUser = new User(); for(int i = 0; i < 10000; i++) { BeanUtils.copyProperties(sourceUser, targetUser); } System.out.println("copy方式:"+(System.currentTimeMillis()-copyStartTime));
long setStartTime = System.currentTimeMillis(); for(int i = 0; i < 10000; i++) { targetUser.setUserName(sourceUser.getUserName()); } System.out.println("set方式:"+(System.currentTimeMillis()-setStartTime)); }}
@Data@AllArgsConstructor@NoArgsConstructorclass User{ private String userName;}
The following is a comparison of execution efficiency results:
 It can be found that the performance gap between conventional set and BeanUtils.copyProperties is very large. Therefore, use BeanUtils.copyProperties with caution.
The above are common pitfalls when using BeanUtils.copyProperties to copy data. Most of these pitfalls are relatively hidden and difficult to troubleshoot when problems arise. Therefore, it is not recommended to use BeanUtils.copyProperties to copy data in business. Any deficiencies in the article are welcome to add and correct.
-end-

This article is shared from the WeChat public account - JD Cloud Developers (JDT_Developers).
If there is any infringement, please contact [email protected] for deletion.
This article participates in the " OSC Source Creation Plan ". You who are reading are welcome to join and share together.

博通宣布终止现有 VMware 合作伙伴计划 B站崩了两次、腾讯“3.29”一级事故……盘点 2023 十大宕机事故“冥场面” Vue 3.4 “灌篮高手”发布 养乐多公司确认 95 G 数据被泄露 MySQL 5.7、魔趣、李跳跳……盘点 2023“停更”的(开源)项目和网站 《2023 中国开源开发者报告》正式发布 回顾 30 年前的 IDE:只有 TUI、背景颜色亮瞎眼…… Julia 1.10 正式发布 Rust 1.75.0 发布 英伟达推出特供中国销售的 GeForce RTX 4090 D
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4090830/blog/10555360