解决BeanUtils.copyProperties不支持复制集合的问题

工作中,经常使用Spring的工具类BeanUtils.copyProperties对bean属性进行复制,这里的复制属于浅复制。且不能复制集合和数组。本文会对该工具进行一些测试。

文末会提出复制集合属性的解决方案

准备工作:准备测试需要的类

@Data
public class Class {
    private People[] member;
    private People teacher;
    private List<People> student;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class People {
    private Integer id;
    private String name;
    private Integer age;
    private Integer sex;
}

测试代码:测试BeanUtils.copyProperties是否支持复制数组和集合,还有解决方案

public static void main(String[] args) {
 // 测试数组的复制
 People[] member = new People[3];
 member[0] = new People(1, "老师", 30, 1);
 member[1] = new People(2, "班长", 15, 1);
 member[2] = new People(3, "学生", 15, 1);
 People[] member1 = new People[]{};
 BeanUtils.copyProperties(member, member1);
 System.out.println("是否可以复制数组:" + (member1.length == 0 ? false : true));
 // 测试List的复制(Map也不能复制,测试略)
 List<People> student = new ArrayList<>();
 student.add(member[1]);
 student.add(member[2]);
 List<People> student1 = new ArrayList<>();
 BeanUtils.copyProperties(student, student1);
 System.out.println("BeanUtils.copyProperties是否可以复制List:" + (student1.isEmpty() ? false : true));
 // 通过JSON工具实现List的复制(不仅仅是List,数组和Map等也可以通过类似方法实现复制,需要有无参构造方法,否则报错)
 student1 = JSON.parseArray(JSON.toJSONString(student), People.class);
 System.out.println("通过JSON工具复制List:" + student1);
 System.out.println("通过JSON工具是否深复制:" + (student.get(0) != student1.get(0) ? true : false));
 // 测试是否深复制
 Class source = new Class();
 source.setMember(member);
 source.setTeacher(member[0]);
 source.setStudent(student);
 Class target = new Class();
 BeanUtils.copyProperties(source, target);
 System.out.println("BeanUtils.copyProperties是否深复制:" + (source.getMember() != target.getMember() ? true : false));
}

测试结果

是否可以复制数组:false
BeanUtils.copyProperties是否可以复制List:false
通过JSON工具复制List:[People(id=2, name=班长, age=15, sex=1), People(id=3, name=学生, age=15, sex=1)]
通过JSON工具是否深复制:true
BeanUtils.copyProperties是否深复制:false

针对List的复制除了通过JSON工具,最简单的就是循环复制集合属性,下面测试两种方法的效率。

public static void main(String[] args) {
 int count = 1;
 System.out.println("测试数据长度:" + count);
 List<People> source = new LinkedList<>();
 List<People> target = new LinkedList<>();
 long start;
 for (int i = 0; i < count; i++) {
     source.add(new People(1, "ly", 25, 1));
 }

 start = System.nanoTime();
 target = JSON.parseArray(JSON.toJSONString(source), People.class);
 System.out.println("JSON:" + (System.nanoTime() - start));

 start = System.nanoTime();
 for (int i = 0; i < count; i++) {
     People p = new People();
     BeanUtils.copyProperties(source.get(i), p);
     target.add(p);
 }
 System.out.println("BeanUtils.copyProperties" + (System.nanoTime() - start));
}

分别测试count=1、10、100、1000、10000、100000的结果。为了防止一起执行出现影响,每次只测试一种复制方法的一种情况,共执行12次。通过对比可以知道,通过JSON复制属性快于BeanUtils,

测试数据长度:1
JSON:154767336
Bean:275182853
测试数据长度:10
JSON:165678435
Bean:275301421
测试数据长度:100
JSON:167937206
Bean:328461161
测试数据长度:1000
JSON:187832969
Bean:315815289
测试数据长度:10000
JSON:297461312
Bean:362763360
测试数据长度:100000
JSON:562035707
Bean:5815319343

通过以下方式解决复制List、Map

public static <T> List copyList(List<T> list) {
    if (CollectionUtils.isEmpty(list)) {
        return new ArrayList();
    }
    return JSON.parseArray(JSON.toJSONString(list), list.get(0).getClass());
}

public static Map<String, Object> copyMap(Map map) {
    return JSON.parseObject(JSON.toJSONString(map));
}

BeanUtils.copyProperties的用法和优缺点

一、简介

BeanUtils提供对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度。

二、用法 

BeanUtils是这个包里比较常用的一个工具类,这里只介绍它的copyProperties()方法。该方法定义如下:

Java代码

public static void copyProperties(java.lang.Object dest,java.lang.Object orig)
throws java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException 

如果你有两个具有很多相同属性的JavaBean,一个很常见的情况就是Struts里的PO对象(持久对象)和对应的ActionForm,例如 Teacher和TeacherForm。

我们一般会在Action里从ActionForm构造一个PO对象,传统的方式是使用类似下面的语句对属性逐个赋值:

//得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;   

//构造Teacher对象
Teacher teacher=new Teacher();   

//赋值
teacher.setName(teacherForm.getName());
teacher.setAge(teacherForm.getAge());
teacher.setGender(teacherForm.getGender());
teacher.setMajor(teacherForm.getMajor());
teacher.setDepartment(teacherForm.getDepartment());   

//持久化Teacher对象到数据库
HibernateDAO.save(teacher);  

而使用BeanUtils后,代码就大大改观了,如下所示:

//得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;   

//构造Teacher对象
Teacher teacher=new Teacher();   

//赋值
BeanUtils.copyProperties(teacher,teacherForm);   

//持久化Teacher对象到数据库
HibernateDAO.save(teacher);  

如果Teacher和TeacherForm间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要程序员手动处理。

例如 Teacher包含modifyDate(该属性记录最后修改日期,不需要用户在界面中输入)属性而TeacherForm无此属性,那么在上面代码的 copyProperties()后还要加上一句:

teacher.setModifyDate(new Date());  

怎么样,很方便吧!除BeanUtils外还有一个名为PropertyUtils的工具类,它也提供copyProperties()方法,作用与 BeanUtils的同名方法十分相似,主要的区别在于后者提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而前者不支持这个功能,但是速度会更快一些。

BeanUtils支持的转换类型如下:

* java.lang.BigDecimal
* java.lang.BigInteger
* boolean and java.lang.Boolean
* byte and java.lang.Byte
* char and java.lang.Character
* java.lang.Class
* double and java.lang.Double
* float and java.lang.Float
* int and java.lang.Integer
* long and java.lang.Long
* short and java.lang.Short
* java.lang.String
* java.sql.Date
* java.sql.Time
* java.sql.Timestamp  

这里要注意一点,java.util.Date是不被支持的,而它的子类java.sql.Date是被支持的。因此如果对象包含时间类型的属性,且希望被转换的时候,一定要使用java.sql.Date类型。否则在转换时会提示argument mistype异常。

三、优缺点 

Apache Jakarta Commons项目非常有用。我曾在许多不同的项目上或直接或间接地使用各种流行的commons组件。其中的一个强大的组件就是BeanUtils。我 将说明如何使用BeanUtils将local实体bean转换为对应的value 对象:

BeanUtils.copyProperties(aValue, aLocal)  

上面的代码从aLocal对象复制属性到aValue对象。它相当简单!它不管local(或对应的value)对象有多少个属性,只管进行复制。我们假设 local对象有100个属性。

上面的代码使我们可以无需键入至少100行的冗长、容易出错和反复的get和set方法调用。这太棒了!太强大了!太有用 了!

现在,还有一个坏消息:使用BeanUtils的成本惊人地昂贵!我做了一个简单的测试,BeanUtils所花费的时间要超过取数 据、将其复制到对应的 value对象(通过手动调用get和set方法),以及通过串行化将其返回到远程的客户机的时间总和。所以要小心使用这种威力!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 解决Beanutils.copyproperties实体类对象不一致的问题

    今天给大家分析一个解决Beanutils.copyproperties实体类对象名不一致的解决方法,一般我们在两个对象拷贝的问题上,我个人用的比较多的就是Beanutils.copyproperties,字段名如果不一致的话就去实体类中使用重载,把当前实体类的对象赋值给另外一个对象,也有用到set(),当然这些也都能解决Beanutils.copyproperties实体类属性不一致的问题,不过今天要给大家分享的是,不用set()和实体类的重构,使用类的反射机制去完成! 话不多说直接开始: 我是

  • BeanUtils.copyProperties在拷贝属性时忽略空值的操作

    BeanUtils.copyProperties忽略空值 使用spring开发的人,对这行代码肯定不陌生,常用于DTO.VO.PO之间的复制. /** * 全属性copy对象 * **/ BeanUtils.copyProperties(Object source, Object target) 但这行代码会将所有的属性都进行copy,有的时候我们想要个别属性不进行复制(比如:null值属性),这时就需要用到另一个方法: /** * 忽略某些属性copy对象 * **/ BeanUtils.co

  • 解决BeanUtils.copyProperties无法成功封装的问题

    BeanUtils.copyProperties无法封装 使用 BeanUtils.copyProperties(user, memeber); 两个类中字段一样,但个别字段无法封装. 期初以为或许是字段的属性不同,仔细检查过还是一样,最后发现,是get.set方法名不同的原因. 如下 user里面有个字段为abc,他的get方法名为getABC(); member里面同样的字段abc,他的get方法名为getAbc(); 最后导致abc的字段无法成功封装 BeanUtils.copyPrope

  • java Beanutils.copyProperties( )用法详解

    这是一篇开发自辩甩锅稿~~~~ 昨天测试小姐姐将我的一个bug单重开了,emmmm....内心OS:就调整下对象某个属性类型这么简单的操作,我怎么可能会出错呢,一定不是我的锅!!but再怎么抗拒,bug还是要改的,毕竟晚上就要发版本了~~ 老老实实将我前天改的部分跟了一遍,恩,完美,没有任何的缺失~~but本应success的测试数据,接口返还的结果确实是false来着,那还是老老实实debug吧. 一步步跟下来,恩,多么顺畅,就说一定不是我的锅~~诶?不对不对,这里的ID值,为啥是null?传

  • 基于Spring BeanUtils的copyProperties方法使用及注意事项

    如下所示: package com.demo; import lombok.Data; import org.springframework.beans.BeanUtils; import java.util.Arrays; import java.util.List; /** * @author xiaobu * @version JDK1.8.0_171 * @date on 2019/10/8 10:04 * @description */ public class BeanUtilsTe

  • 如何使用BeanUtils.copyProperties进行对象之间的属性赋值

    1.使用org.springframework.beans.BeanUtils.copyProperties方法进行对象之间属性的赋值,避免通过get.set方法一个一个属性的赋值 /** * 对象属性拷贝 <br> * 将源对象的属性拷贝到目标对象 * * @param source 源对象 * @param target 目标对象 */ public static void copyProperties(Object source, Object target) { try { BeanU

  • java使用BeanUtils.copyProperties踩坑经历

    1. 原始转换 提起对象转换,每个程序员都不陌生,比如项目中经常涉及到的DO.DTO.VO之间的转换,举个例子,假设现在有个OrderDTO,定义如下所示: public class OrderDTO { private long id; private Long userId; private String orderNo; private Date gmtCreated; // 省略get.set方法 } 有个OrderVO,定义如下所示: public class OrderVO { pr

  • 解决BeanUtils.copyProperties不支持复制集合的问题

    工作中,经常使用Spring的工具类BeanUtils.copyProperties对bean属性进行复制,这里的复制属于浅复制.且不能复制集合和数组.本文会对该工具进行一些测试. 文末会提出复制集合属性的解决方案 准备工作:准备测试需要的类 @Data public class Class { private People[] member; private People teacher; private List<People> student; } @Data @NoArgsConstr

  • 解决BeanUtils.copyProperties之大坑

    目录 BeanUtils.copyProperties大坑 BeanUtils.copyProperties() 用法及区别 因为两个类引入了两个不同的BeanUtils类 例如 BeanUtils.copyProperties大坑 两个不同的包(springframework , apache)中有一个相同名字的类,相同的方法,方法的作用相同,参数个数相同.就是参数位置不同,是相反的.? import org.springframework.beans.BeanUtils; import or

  • BeanUtils.copyProperties复制不生效的解决

    目录 前言 问题的排查 问题的扩展 前言 呵呵 前端时间使用 BeanUtils.copyProperties 的时候碰到了一个这样的问题 我有两个实体, 有同样的属性, 一个有给定的属性的 getter, 另外一个有 给定的属性的 setter, 但是 我使用 BeanUtils.copyProperties 的时候 把来源对象的这个属性 复制不到 目标对象上面 然后 当时也跟踪了一下代码, 然后 这里整理一下 改代码片段吧 然后在调试的过程中 也发现了一些其他的问题, 呵呵 算是额外的了解吧

  • BeanUtils.copyProperties复制属性失败的原因及解决方案

    目录 BeanUtils.copyProperties复制属性失败 描述 解决办法 BeanUtils.copyProperties应用的改进 为解决这个问题我重写了部分spring BeanUtils的代码 BeanUtils.copyProperties复制属性失败 描述 在JavaE中使用 BeanUtils.copyProperties,把A对象的name.age等属性复制到B对象中,A与B对象的类型不同.出现的问题是复制属性失败,根本原因是 BeanUtils找不到set.get方法.

  • BeanUtils.copyProperties()拷贝id属性失败的原因及解决

    目录 BeanUtils.copyProperties()拷贝id属性失败 部分代码如下 解决方法 BeanUtils.copyProperties 出错 BeanUtils.copyProperties()拷贝id属性失败 po类中id有值,但是使用BeanUtils.copyProperties()拷贝出的vo类id属性为null,检查后发现是因为po继承的父类声明了一个泛型. 部分代码如下 public abstract class AbstractEntity<ID extends Se

  • BeanUtils.copyProperties复制对象结果为空的原因分析

    目录 BeanUtils.copyProperties复制对象结果为空原因 正确的包 错误的包 两个类的区别 BeanUtils.copyProperties拷贝没成功的坑,记录解决原因 具体如下 BeanUtils.copyProperties复制对象结果为空原因 细心比对,发现原来是导错了包导致的 正确的包 import org.springframework.beans.BeanUtils; 错误的包 import org.apache.commons.beanutils.BeanUtil

  • BeanUtils.copyProperties()所有的空值不复制问题

    目录 BeanUtils.copyProperties()所有的空值不复制 第一种情况 第二种情况 BeanUtils.copyProperties()的用法和注意点 属性为null也会被复制,内部类不会复制过去 注意点一 注意点二 BeanUtils.copyProperties()所有的空值不复制 第一种情况 所有为空值的属性都不copy 直接上代码吧~ public class UpdateUtil { /** * 所有为空值的属性都不copy * * @param source * @p

  • 关于BeanUtils.copyProperties(source, target)的使用

    BeanUtils.copyProperties 首先,使用的是org.springframework.beans.BeanUtils; source 来源, target 目标 顾名思义, BeanUtils.copyProperties(source, target); 第一个参数是需要拷贝的目标,第二个参数是拷贝后的目标. 因为这个方法有很多种情况,容易分不清,所以今天测了一下不同情况下的结果如何. 1.target里面有source里没有的属性 并且此属性有值时 2.target和sou

随机推荐