精华内容
下载资源
问答
  • Java 对象copy之BeanCopier工具类的使用

    千次阅读 2018-11-23 15:20:01
    业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度,代码因此变得臃肿不堪,使用一些方便的对象拷贝工具类将是很好的...

    对象拷贝的应用现状简介:

    业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度,代码因此变得臃肿不堪,使用一些方便的对象拷贝工具类将是很好的选择。

    目前流行的较为公用认可的工具类:

    Apache的两个版本:(反射机制)

    org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig)

    org.apache.commons.beanutils.BeanUtils.copyProperties(Object dest, Object orig)

    Spring版本:(反射机制)

    org.springframework.beans.BeanUtils.copyProperties(Object source, Object target, Class editable, String[] ignoreProperties)

    cglib版本:(使用动态代理,效率高)

    net.sf.cglib.beans.BeanCopier.copy(Object paramObject1, Object paramObject2, Converter paramConverter)

    原理简介

    反射类型:(apache

    都使用静态类调用,最终转化虚拟机中两个单例的工具对象。

    public BeanUtilsBean()

    {

      this(new ConvertUtilsBean(), new PropertyUtilsBean());

    }

    ConvertUtilsBean可以通过ConvertUtils全局自定义注册。

    ConvertUtils.register(new DateConvert(), java.util.Date.class);

    PropertyUtilsBean的copyProperties方法实现了拷贝的算法。

    1、  动态bean:orig instanceof DynaBean:Object value = ((DynaBean)orig).get(name);然后把value复制到动态bean类

    2、  Map类型:orig instanceof Map:key值逐个拷贝

    3、  其他普通类::从beanInfo【每一个对象都有一个缓存的bean信息,包含属性字段等】取出name,然后把sourceClass和targetClass逐个拷贝

    Cglib类型:BeanCopier

    copier = BeanCopier.create(source.getClass(), target.getClass(), false);

    copier.copy(source, target, null);

     

    Create对象过程:产生sourceClass-》TargetClass的拷贝代理类,放入jvm中,所以创建的代理类的时候比较耗时。最好保证这个对象的单例模式,可以参照最后一部分的优化方案。

    创建过程:源代码见jdk:net.sf.cglib.beans.BeanCopier.Generator.generateClass(ClassVisitor)

    1、  获取sourceClass的所有public get 方法-》PropertyDescriptor[] getters

    2、  获取TargetClass 的所有 public set 方法-》PropertyDescriptor[] setters

    3、  遍历setters的每一个属性,执行4和5

    4、  按setters的name生成sourceClass的所有setter方法-》PropertyDescriptor getter【不符合javabean规范的类将会可能出现空指针异常】

    5、  PropertyDescriptor[] setters-》PropertyDescriptor setter

    6、  将setter和getter名字和类型 配对,生成代理类的拷贝方法。

    Copy属性过程:调用生成的代理类,代理类的代码和手工操作的代码很类似,效率非常高。

     

    上述这几种方式速度最快的是BeanCopier,默认只复制名称和类型相同的字段,还会对date为空的情况不进行复制。

    我认为这样做最好,比如对象A的值复制到B中,我们把相同的进行复制,把不同的,也就是需要我们个性化的一些字段,单独出来用get来赋值,这样程序就会很明确,重点也就聚焦在了不同的地方。

     

    缺陷预防

     

    你不知道这些陷阱吧?

     

    陷阱条件

    Apache- PropertyUtils

    Apache- BeanUtils

    Spring-  BeanUtils

    Cglib-

    BeanCopier

    是否可以扩展

    useConvete功能

    NO

    Yes

    Yes

    Yes,但比较难用

    (sourceObject,targetObject)的顺序

    逆序

    逆序

    OK

     

    OK

    对sourceObject特殊属性的限制:(Date,BigDecimal等)【见备注1】

    OK

    NO,异常出错

    OK

    OK

    相同属性名,且类型不匹配时候的处理

    【见备注2】

    异常,拷贝部分属性,非常危险

    OK,并能进行初级转换,Long和Integer互转

    异常,拷贝部分属性

    OK,但是该属性不拷贝

    Get和set方法不匹配的处理

    【见备注3】

    OK

    OK

    OK

    创建拷贝的时候报错,无法拷贝任何属性(当且仅当sourceClass的get方法超过set方法)

     

     

    备注1

     

    对targetObject特殊属性的限制:(Date,BigDecimal等)

    原因:dateTimeConveter的conveter没有对null值的处理

    public class ErrorBeanUtilObject { //此处省略getter,setter方法

        private String name;

        private java.util.Date date;

    }

     public class ErrorBeanUtilsTest {  

        public static void main(String args[]) throws Throwable  {  

        ErrorBeanUtilObject from = new ErrorBeanUtilObject(); 

        ErrorBeanUtilObject to = new ErrorBeanUtilObject();  

        //from.setDate(new java.util.Date());

        from.setName("TTTT");

        org.apache.commons.beanutils.BeanUtils.copyProperties(to, from);//如果from.setDate去掉,此处出现conveter异常

        System.out.println(ToStringBuilder.reflectionToString(from));

        System.out.println(ToStringBuilder.reflectionToString(to));

        }  

    }

     

     

    备注2

     

    相同属性名,且类型不匹配时候的处理

    原因:这两个工具类不支持同名异类型的匹配 !!!【包装类Long和原始数据类型long是可以的】

    public class TargetClass {  //此处省略getter,setter方法

        private Long num;  

        private String name;

    }

    public class TargetClass {  //此处省略getter,setter方法

        private Long num;

        private String name;

    }

    public class ErrorPropertyUtilsTest {        

        public static void main(String args[]) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException  {  

            SourceClass from = new SourceClass();  

            from.setNum(1);

            from.setName("name"); 

            TargetClass to = new TargetClass();  

            org.apache.commons.beanutils.PropertyUtils.copyProperties(to, from); //抛出参数不匹配异常

            org.springframework.beans.BeanUtils.copyProperties(from, to);

    //抛出参数不匹配异常

            System.out.println(ToStringBuilder.reflectionToString(from));    

            System.out.println(ToStringBuilder.reflectionToString(to));  

        }  

    }

     

     

    备注3

     

    Get和set方法不匹配的处理

    public class ErrorBeanCopierTest {    

        /**

         * 从该用例看出BeanCopier.create的target.class 的每一个get方法必须有队形的set方法

         * @param args

         */

        public static void main(String args[]) {  

            BeanCopier copier = BeanCopier.create(UnSatifisedBeanCopierObject.class, SourceClass.class,false);

            copier = BeanCopier.create(SourceClass.class, UnSatifisedBeanCopierObject.classfalse); //此处抛出异常创建 

        }  

    }

    class UnSatifisedBeanCopierObject {   

        private String name;

        private Long num;

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public Long getNum() {

           return num;

        }

    //  public void setNum(Long num) {

    //     this.num = num;

    //  }

    }

     

     

     

     

    优化方案

    一些优化和改进

    增强apache的beanUtils的拷贝属性,注册一些新的类型转换

    public class BeanUtilsEx extends BeanUtils

    {

      public static void copyProperties(Object dest, Object orig)

      {

        try

        {

          BeanUtils.copyProperties(dest, orig);

        } catch (IllegalAccessException ex) {

          ex.printStackTrace();

        } catch (InvocationTargetException ex) {

          ex.printStackTrace();

        }

      }

      static

      {

        ConvertUtils.register(new DateConvert(), java.util.Date.class);

        ConvertUtils.register(new DateConvert(), java.sql.Date.class);

        ConvertUtils.register(new BigDecimalConvert(), BigDecimal.class);

      }

    }

    将beancopier做成静态类,方便拷贝

    public class BeanCopierUtils {

         public static Map<String,BeanCopier> beanCopierMap = new HashMap<String,BeanCopier>();

        

         public static void copyProperties(Object source, Object target){

             String beanKey =  generateKey(source.getClass(), target.getClass());

             BeanCopier copier =  null;

             if(!beanCopierMap.containsKey(beanKey)){

                  copier = BeanCopier.create(source.getClass(), target.getClass(), false);

                  beanCopierMap.put(beanKey, copier);

             }else{

                  copier = beanCopierMap.get(beanKey);

             }

             copier.copy(source, target, null);

         }   

         private static String generateKey(Class<?> class1,Class<?>class2){

             return class1.toString() + class2.toString();

         }

    }

    修复beanCopier对set方法强限制的约束

    改写net.sf.cglib.beans.BeanCopier.Generator.generateClass(ClassVisitor)方法

    将133行的

    MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());

    预先存一个names2放入

    /* 109 */       Map names2 = new HashMap();

    /* 110 */       for (int i = 0; i < getters.length; ++i) {

    /* 111 */         names2.put(setters[i].getName(), getters[i]);

    /*     */       }

    调用这行代码前判断查询下,如果没有改writeMethod则忽略掉该字段的操作,这样就可以避免异常的发生。

     

    下面我封装一下(大家可以直接用):


    public class BeanCopierUtils {
        public static Map<String,BeanCopier> beanCopierMap = new HashMap<String,BeanCopier>();
        public static void copyProperties(Object source, Object target){
            String beanKey =  generateKey(source.getClass(), target.getClass());
            BeanCopier copier =  null;
            if(!beanCopierMap.containsKey(beanKey)){
                 copier = BeanCopier.create(source.getClass(), target.getClass(), false);
                 beanCopierMap.put(beanKey, copier);
            }else{
                 copier = beanCopierMap.get(beanKey);
            }
            copier.copy(source, target, null);
        }   

        private static String generateKey(Class<?> class1,Class<?>class2){
            return class1.toString() + class2.toString();
        }
    }

     

     

     

    展开全文
  • 实用的对象copy工具

    2019-07-01 11:15:27
    package ... import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; ... * notes 对象工具类 * author xiaoming.chen * create 2018/11/2 000...
    package com.pos.common.utils;
    
    import org.springframework.util.CollectionUtils;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * notes 对象工具类
     * author xiaoming.chen
     * create 2018/11/2 0002 15:40
     **/
    public class BeanUtils {
    
        /**
         * 通过 tClass 生成示例并且将 source 对应的字段 copy
         * @param source 源对象
         * @param tClass 期望对象类型
         * @param <S> 源对象
         * @param <T> 期望对象
         * @return 期望对象实例
         */
        public static <S,T> T copyProperties(S source, Class<T> tClass) {
            try {
                T target = tClass.newInstance();
                if (null == source) {
                    return target;
                }
                org.springframework.beans.BeanUtils.copyProperties(source, target);
                return target;
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException( String.format("%s must declaring none arguments constructor!", tClass.getTypeName()));
            }
        }
    
        /**
         * 根据类型生成,生成转换的新列表
         *
         * @param tClass 目标列表类型
         * @param list   原列表数据
         * @param <S>    source class
         * @param <T>    target class
         * @return 目标列表
         */
        public static <S, T> List<T> assemble(Class<T> tClass, List<S> list){
            if (CollectionUtils.isEmpty(list)) {
                return new ArrayList<>();
            }
            List<T> lists=new ArrayList<>(list.size());
            for (S s : list) {
                lists.add(BeanUtils.copyProperties(s, tClass));
            }
            return lists;
        }
    
        /**
         * 提供源数据列表和转换规则,生成新的列表
         *
         * @param list              原列表
         * @param transferInterface 转换规则接口实现
         * @param <S>   source class
         * @param <T>   target class
         * @return 转换后的列表
         */
        public static <S, T> List<T>  assemble(List<S> list, TransferInterface<S, T> transferInterface){
            if (CollectionUtils.isEmpty(list)) {
                return new ArrayList<>();
            }
            List<T> lists=new ArrayList<>(list.size());
            for (S s : list) {
                lists.add(transferInterface.transfer(s));
            }
            return lists;
        }
    
        public interface TransferInterface<S, T>  {
            T transfer(S s);
        }
    }
    
    展开全文
  • java 对象拷贝工具

    千次阅读 2020-02-22 17:03:07
    import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class ObjectCopy { ... * 复制对象值 不复制对象地址 * * @param src * @param dest */ public ...
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    
    public class ObjectCopy {
        /**
         * 复制对象值 不复制对象地址
         *
         * @param src
         * @param dest
         */
        public static void copy(Object src, Object dest) {
    
            Map<String, Object> srcMap = new HashMap<String, Object>();
            Field[] srcFields = src.getClass().getDeclaredFields();
            for (Field fd : srcFields) {
                try {
                    srcMap.put(fd.getName(), fd.get(src)); //获取属性值
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            Field[] destFields = dest.getClass().getDeclaredFields();
            for (Field fd : destFields) {
                if (srcMap.get(fd.getName()) == null) {
                    continue;
                }
                try {
                    fd.set(dest, srcMap.get(fd.getName())); //给属性赋值
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    
    展开全文
  • Java复制对象与集合工具

    千次阅读 2019-03-31 19:13:04
    项目中经常需要将某个对象的属性值复制给另一个对象,或者将一个集合复制到另一个集合。利用spring提供的BeanUtils,自己简单封装了一个工具类。 public class CopyUtils { /** * 复制集合 */ public static &...

    项目中经常需要将某个对象的属性值复制给另一个对象,或者将一个集合复制到另一个集合。利用spring提供的BeanUtils,自己简单封装了一个工具类。

    public class CopyUtils {
    
        /**
         * 复制集合
         */
        public static <T,K> List<T> copyList(List<K> sourceList, Class<T> clazz) {
            if (CollectionUtils.isEmpty(sourceList)) {
                return null;
            }
    
            ArrayList<T> target = new ArrayList<>();
            sourceList.forEach(k -> target.add(convert(k, clazz)));
            return target;
        }
    
        /**
         * 复制对象
         */
        public static <T,K> T convert(K source, Class<T> clazz) {
            T t = BeanUtils.instantiate(clazz);
            BeanUtils.copyProperties(source, t);
            return t;
        }
    
    }
    
    展开全文
  • 对象拷贝工具类BeanutilsCopy

    千次阅读 2016-04-28 23:43:32
    mport java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List;import org.apache.commons.beanutils.BeanUtils; import org.apache.log4j.Logger; import org.dozer...
  • Java Bean Copy 性能大比拼

    千次阅读 2019-03-29 08:00:36
    Java Bean Copy 性能大比拼 简介 Bean 拷贝在工作中被大量使用,可以大幅度的提高工作量。本文对常用的 Bean copy 工具进行了压力测试,方便大家选择更加适合自己的工具。本篇文章是mica cglib 增强——【01】cglib...
  • java对象复制和属性值复制工具

    千次阅读 2017-11-30 16:19:10
    两个不同类型的对象中有字段名称不区分大小写的情况下一样,字段含义一样,需要组装到另一个对象中去,然后就写了一个这种工具类 我的类型比较特殊,老系统和新系统的对象命名大小写命名不一致,并且字段相同类型也...
  • java 对象复制 集合复制工具

    千次阅读 2019-09-29 10:44:52
    * 将源POJO对象数据复制给目标POJO对象的同名属性 * * @date 2018年12月4日 * @version 1.0 * * @param source 源 * @param target 目标 * @param * @param * @return 目标 */ public static , T> T ...
  • Java BeanUtils对象复制工具类及方法

    千次阅读 2018-12-14 17:02:37
    java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); Set<String> emptyNames = new HashSet(); for (java.beans.PropertyDescriptor pd : pds) { Object srcValue = src.getPropertyValue...
  • JAVA复制对象和集合的工具类 因为BeanUtils.copyProperties(Object source, Object target),只能复制对象,不能复制数组和集合,所以决定写个工具类来解决 public class CopyUtils { /** * 复制对象 */ public ...
  • java属性copy简单使用

    千次阅读 2017-10-13 13:46:59
    * Description:java对象拷贝 * 注意事项: * 使用spring的BeanUtils不用抛异常,而使用Apache的BeanUtils必须抛异常(反射),否则编译报错 * 使用BeanUtils的copyProperties时,如果实体B想要copy实体A,而实体...
  • Java对象的拷贝与复制

    千次阅读 2018-03-09 15:25:10
    Java对象Copy引用CSDN博客地址:http://m.blog.csdn.net/chenssy/article/details/12952063拷贝一个Java对象,这种需求在程序中应该常用,一下有两种实现方式,浅拷贝和深度拷贝1.浅拷贝我们知道在Java中存在这个...
  • 最近博主有一个项目,需要判断一个JavaBean中的对象属性是否都为null 一开始,博主以为直接用if(Bean == null) 来判断(傻了) ...下面po出代码,大家直接copy就行。 import lombok.extern.slf4j.Slf4j; ...
  • java对象拷贝

    万次阅读 多人点赞 2017-03-22 15:49:59
    java赋值是复制对象引用,如果我们想要得到一个对象的副本,使用赋值操作是无法达到目的的:@Test public void testassign(){ Person p1=new Person(); p1.setAge(31); p1.setName("Peter"); Person p2=p1; ...
  • 在微服务架构的项目中,我们经常会遇到外观模式设计,把核心的数据结构隐藏起来,暴露对外的request和response...关于java对象与对象之间的转换,可行的方式有以下几种 1、org.apache.commons.beanutils.Property...
  • java对象clone()方法

    万次阅读 多人点赞 2018-05-10 18:37:47
    java赋值是复制对象引用,如果我们想要得到一个对象的副本,使用赋值操作是无法达到目的的: @Test public void testassign(){ Person p1=new Person(); p1.setAge(31); p1.setName("Peter"); Person p2=p1; ...
  • Java面向对象

    千次阅读 2016-05-29 14:34:23
    java 学习:面向对象: 面向对象的基本概念: java是面向对象的程序语言,c是面向过程的程序语言,各有特长。 - 面向对象的三个主要特征: 封装性: 对外部不可见,可以保护程序中的某些内容。 继承性:扩展功能。 ...
  • JavaBean对象属性copy

    千次阅读 2019-07-15 20:37:12
      在日常编码中,经常会遇到DO、DTO对象之间的转换,如果对象本身的属性比较少的时候,那么采用Hard Code工作量也不大,但如果对象的属性比较多的情况下,Hard Code效率就比较低。这时候就要使用其它工具类来进行...
  • 不同类的属性值Copy工具类BeanCopyUtil

    千次阅读 2019-04-08 10:15:42
    package ... import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** ...
  • javacopy 一个list集合的方法

    千次阅读 2017-03-19 17:36:00
    java将一个list里的数据转移到另外一个list,可以使用for语句,一次使用add方法,示例如下: ArrayList list1=new ArrayList(); list1.add("1"); list1.add("2"); list1.add("3"); ArrayList list2=new ...
  • 使用redis存储Java对象

    千次阅读 2018-04-24 16:54:17
    Redis的key和value都支持二进制安全的字符串,存储Java对象不是问题,下面我们看一下如何来实现。1要存储的对象现在写一个很土的Java Bean,包含两个字段,id和name,类名叫做Person。为了实现序列化需求,该类实现...
  • java 复制非空对象属性值

    千次阅读 2017-02-15 11:31:27
    用于对象拷贝,spring 和 Apache都提供了相应的工具类方法,BeanUtils.copyProperties 但是对于非空属性拷贝就需要自己处理了 在这里借用spring中org.springframework.beans.BeanUtils类提供的方
  • Java常用公共工具记录

    千次阅读 2018-07-03 16:23:01
    转载于:https://blog.csdn.net/Evankaka/article/details/726146011、日期处理工具import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date; /** * 日期常用格式转换 */public class ...
  • 项目环境: jdk1.8+spring4.3.12 一、问题描述及试用场景:...另一方面,如果数据被更改,服务端通过加密参数与前端传过来的密文比较即可判断出数据是否已被更改。常用加密方式有:MD5,HMAC,RSA,SHA等。 二、样例代
  • 随后分别介绍了4种现有的主流Java静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能、特性等方面对它们进行分析和比较,希望能够帮助Java软件开发人员了解静态代码分析工具,并选择合适的工具应用到...
  • Java中的工具类究竟如何命名?

    千次阅读 2019-11-28 14:43:44
    Java中的工具类究竟如何命名? 先来几个例子 JDK自带工具类 Arrays.asList(); Objects.equals(); Collections.sort(); Spring框架工具类 StringUtils.isEmpty(); CollectionUtils.isEmpty() FileCopyUtils....
  • Java对象复制非空属性

    千次阅读 2019-02-25 15:06:15
    引用org.springframework.beans.BeanUtils类提供的方法copyProperties(Object ... ignoreProperties) 用于对象拷贝,spring 和 Apache都提供了相应的工具类方法,BeanUtils.copyProperties package com.mixislink...
  • JAVA对象拷贝分为两种方式,一种是引用拷贝,一种是对象拷贝 引用拷贝:和对象拷贝的不同之处在于,引用拷贝只会生成一个新的对象引用地址,但两个地址其最终指向的还是同一个对象; 对象拷贝:这种方式会重新生成...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,526
精华内容 30,210
关键字:

java对象copy工具比较

java 订阅