BeanUtils 深度Copy List

/**
 * Bean操作工具类
 */
public class BeanUtils {

    /**
     * Bean复制,换用Spring的copyProperties方法,防止目标bean使用@Accessors(chain=true)后,CGLib的对象拷贝有问题
     *
     * @param srcBean    源bean对象
     * @param targetBean 目标bean对象
     */
    public static void copyBean(Object srcBean, Object targetBean) {
        if (srcBean == null || targetBean == null) {
            return;
        }
        org.springframework.beans.BeanUtils.copyProperties(srcBean, targetBean);
    }

    /**
     * Bean复制,浅复制
     *
     * @param srcBean     源Bean对象
     * @param targetClass 目标对象Class
     * @param <T>         目标类型
     * @return 目标Bean
     */
    public static <T> T copyBean(Object srcBean, Class<T> targetClass) {
        if (srcBean == null) {
            return null;
        }
        try {
            T targetBean = targetClass.newInstance();
            copyBean(srcBean, targetBean);
            return targetBean;
        } catch (Exception e) {
            throw new RuntimeException("对象拷贝异常", e);
        }
    }

    /**
     * List复制,属浅复制
     *
     * @param srcList     源List对象
     * @param targetClass 目标列表Bean类
     * @param <T>         列表Bean Type
     * @return 目标列表
     */
    public static <T> List<T> copyBeanList(List srcList, Class<T> targetClass) {
        List<T> targetBeanList = new ArrayList<>();
        if (srcList == null || srcList.isEmpty()) {
            return targetBeanList;
        }
        try {
            for (Object srcObj : srcList) {
                T targetBean = targetClass.newInstance();
                copyBean(srcObj, targetBean);
                targetBeanList.add(targetBean);
            }
        } catch (Exception e) {
            throw new RuntimeException("对象拷贝异常", e);
        }
        return targetBeanList;
    }

    /**
     * Bean复制,深度复制
     *
     * @param srcBean     源Bean对象
     * @param targetClass 目标对象Class
     * @param <T>         目标类型
     * @return 目标Bean
     */
    public static <T> T deepCopyBean(Object srcBean, Class<T> targetClass) {
        if (srcBean == null) {
            return null;
        }
        try {
            T targetBean = targetClass.newInstance();
            deepCopyBean(srcBean, targetBean);
            return targetBean;
        } catch (Exception e) {
            throw new RuntimeException("对象拷贝异常", e);
        }
    }

    /**
     * Bean复制,深度复制
     *
     * @param source 源Bean对象
     * @param target 目标Bean对象
     */
    public static void deepCopyBean(Object source, Object target) {
        Class<?> actualEditable = target.getClass();
        PropertyDescriptor[] targetPds = org.springframework.beans.BeanUtils.getPropertyDescriptors(actualEditable);

        for (PropertyDescriptor targetPd : targetPds) {
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null) {
                PropertyDescriptor sourcePd = org.springframework.beans.BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null &&
                            ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            //主要的核心在这里:针对Field的类型为Collection类型的处理
                            if (value instanceof Collection) {
                                Type writeType = writeMethod.getGenericParameterTypes()[0];
                                Type readType = readMethod.getGenericReturnType();
                                Type writeActualType;
                                //当 source 中 Collection类型的Field的泛型和target中的Field的泛型类型不一致的时候 需要进行深度拷贝
                                if (writeType instanceof ParameterizedType
                                        && readType instanceof ParameterizedType
                                        && (writeActualType = ((ParameterizedType) writeType).getActualTypeArguments()[0]) != ((ParameterizedType) readType).getActualTypeArguments()[0]) {
                                    //这里只是简单的调用反射来实例化,因此原集合类型必须要有无参构造,比如Arrays.asList创建的集合则无法拷贝,会抛出异常
                                    Collection sourceList = (Collection) value;
                                    Collection actualValue;
                                    //兼容Arrays.asList创建的集合,获取类名为java.util.Arrays$ArrayList,则直接设置actualValue为new ArrayList,避免因没有无参构造调用newInstance报错的问题
                                    if (value.getClass().toString().equals("class java.util.Arrays$ArrayList") || value.getClass().toString().equals("class java.util.Collections$EmptyList")) {
                                        actualValue = new ArrayList();
                                    } else {
                                        actualValue = (Collection) value.getClass().newInstance();
                                    }
                                    actualValue.clear();
                                    for (Object subSource : sourceList) {
                                        Object subTarget = ((Class) writeActualType).newInstance();
                                        deepCopyBean(subSource, subTarget);
                                        actualValue.add(subTarget);
                                    }
                                    value = actualValue;
                                }
                            }
                            writeMethod.invoke(target, value);
                        } catch (Throwable ex) {
                            throw new FatalBeanException(
                                    "Could not copy property '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }
    }

    /**
     * List复制,深度复制
     *
     * @param srcList     源List
     * @param targetClass 目标List元素类
     * @param <T>         目标元素类型
     * @return 目标List
     */
    public static <T> List<T> deepCopyBeanList(List srcList, Class<T> targetClass) {
        return deepCopyBeanList(srcList, targetClass, null);
    }

    /**
     * 深度克隆
     *
     * @param srcList       源List
     * @param targetClass   目标Class
     * @param cloneConsumer 克隆消费类,可处理自定义转换属性
     * @param <T>           目标类型
     * @param <R>           源类型
     */
    public static <T, R> List<T> deepCopyBeanList(List<R> srcList, Class<T> targetClass, BiConsumer<R, T> cloneConsumer) {
        List<T> targetBeanList = new ArrayList<>();
        if (srcList == null || srcList.isEmpty()) {
            return targetBeanList;
        }
        try {
            for (R srcObj : srcList) {
                T targetBean = targetClass.newInstance();
                deepCopyBean(srcObj, targetBean);
                if (cloneConsumer != null) {
                    cloneConsumer.accept(srcObj, targetBean);
                }
                targetBeanList.add(targetBean);
            }
        } catch (Exception e) {
            throw new RuntimeException("对象拷贝异常", e);
        }
        return targetBeanList;
    }

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BeanUtils.copyProperties 方法是Apache Commons BeanUtils 库提供的一个用于属性拷贝的工具方法,它用于将一个JavaBean对象的属性值拷贝到另一个JavaBean对象中。然而,这个方法并不支持深度拷贝,它只会将源对象的属性值逐个复制到目标对象中。 如果你需要实现深度拷贝,即拷贝对象及其所有引用对象的属性值,你可以考虑使用其他的工具类库,比如: 1. 使用Java的序列化机制:将源对象进行序列化,然后再反序列化到目标对象中。这种方式可以实现对象及其引用对象的完整拷贝,但要求被拷贝的对象及其引用对象都必须实现Serializable接口。 2. 使用第三方工具库,比如Apache Commons Lang 库中的SerializationUtils类,它提供了一些静态方法用于实现深度拷贝。 下面是使用Apache Commons Lang 库进行深度拷贝的示例代码: ```java import org.apache.commons.lang3.SerializationUtils; public class DeepCopyExample { public static void main(String[] args) { // 创建源对象 Person sourcePerson = new Person("John", 25); // 使用SerializationUtils进行深度拷贝 Person clonedPerson = SerializationUtils.clone(sourcePerson); // 修改源对象的属性值 sourcePerson.setName("Jane"); sourcePerson.setAge(30); // 输出拷贝后的目标对象的属性值 System.out.println("Cloned person: " + clonedPerson.getName() + ", " + clonedPerson.getAge()); } } class Person implements Serializable { private String name; private int age; // 省略构造方法、getter和setter // 注意:这里需要提供无参构造方法,便于序列化和反序列化过程中的对象创建 public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } } ``` 这样,你就可以通过使用 SerializationUtils 类的 clone 方法来实现深度拷贝,从而将源对象及其所有引用对象的属性值复制到目标对象中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值