使用Hutool实现深复制,非序列化

思路

  • 递归复制

测试代码

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ReflectUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;

public class DeepCopyPropertiesTest {
    
    
    public static void main(String[] args) {
    
    
        List<BeanA> beanAList = CollUtil.newArrayList();
        for (int i = 0; i < 3; i++) {
    
    
            BeanA beanA = new BeanA("beanA" + i, i);
            beanAList.add(beanA);
        }
        BeanA beanA = new BeanA("beanAOutSideTheList", 30);
        Map<String, BeanA> map = new HashMap<>();
        map.put("aa", beanA);
        BeanB beanB = new BeanB("beanB", beanAList, beanA, map);
        BeanB copyBeanB = new BeanB();
        BeanUtil.deepCopyProperties(beanB, copyBeanB);
        Console.log(beanB.getBeanA() == copyBeanB.getBeanA());
        Console.log(beanB.getBeanAList().get(1) == copyBeanB.getBeanAList().get(1));
        Console.log(beanB.getMap().get("aa") == copyBeanB.getMap().get("aa"));
        Console.log(beanB);
        Console.log(copyBeanB);
    }
}

BeanA

public class BeanA {
    
    
    private String name = "beanA";
    private int age = 20;

    public BeanA() {
    
    
    }

    public BeanA(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "BeanA{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

BeanB

public class BeanB {
    
    

    private String name = "beanB";
    @DeepCopy
    private List<BeanA> beanAList;
    @DeepCopy
    private BeanA beanA;
    @DeepCopy
    private Map<String, BeanA> map;

    public BeanB() {
    
    
    }

    public BeanB(String name, List<BeanA> beanAList, BeanA beanA, Map<String, BeanA> map) {
    
    
        this.name = name;
        this.beanAList = beanAList;
        this.beanA = beanA;
        this.map = map;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public List<BeanA> getBeanAList() {
    
    
        return beanAList;
    }

    public void setBeanAList(List<BeanA> beanAList) {
    
    
        this.beanAList = beanAList;
    }

    public BeanA getBeanA() {
    
    
        return beanA;
    }

    public void setBeanA(BeanA beanA) {
    
    
        this.beanA = beanA;
    }

    public Map<String, BeanA> getMap() {
    
    
        return map;
    }

    public void setMap(Map<String, BeanA> map) {
    
    
        this.map = map;
    }

    @Override
    public String toString() {
    
    
        return "BeanB{" +
                "name='" + name + '\'' +
                ", beanAList=" + beanAList +
                ", beanA=" + beanA +
                ", map=" + map +
                '}';
    }
}

@DeepCopy

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({
    
    ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DeepCopy {
    
    
}

    /**
     * 深度复制,所有带有@{@link DeepCopy}的属性都会被深度复制,支持复制list和map,如果对象不包含无参构造方法或者以自身作为参数的单参数构造方法,需要自行将新的实例放入newInstanceMap中,要忽略的属性放在ignorePropertiesMap中,顶级的key是root,其余的是属性的名称
     *
     * @param source              源对象
     * @param target              目标对象
     * @param newInstanceMap      新实例
     * @param ignorePropertiesMap 复制时忽略属性
     */
    public static void deepCopyProperties(Object source, Object target, Map<Type, Object> newInstanceMap, Map<String, String[]> ignorePropertiesMap) {
    
    
        String[] ignoreProperties = null;
        if (ignorePropertiesMap != null) {
    
    
            ignoreProperties = ignorePropertiesMap.get("root");
        }
        BeanUtil.copyProperties(source, target, ignoreProperties);
        recursion(source, target, newInstanceMap, ignorePropertiesMap);
    }

    @SuppressWarnings("unused")
    public static void deepCopyProperties(Object source, Object target) {
    
    
        deepCopyProperties(source, target, null, null);
    }

    @SuppressWarnings("unused")
    public static void deepCopyProperties(Object source, Object target, Map<Type, Object> newInstanceMap) {
    
    
        deepCopyProperties(source, target, newInstanceMap, null);
    }

    @SuppressWarnings({
    
    "unchecked", "rawtypes"})
    public static void recursion(Object source, Object target, Map<Type, Object> newInstanceMap, Map<String, String[]> ignorePropertiesMap) {
    
    
        if (source instanceof Collection) {
    
    
            copyCollection((Collection<Object>) source, (Collection<Object>) target, newInstanceMap, ignorePropertiesMap);
            return;
        }
        Field[] fields = ReflectUtil.getFields(source.getClass());
        for (Field field : fields) {
    
    
            Class<?> fieldType = field.getType();
            String fieldName = field.getName();
            if (fieldType.isPrimitive()) {
    
    
                continue;
            }
            Object fieldValue = ReflectUtil.getFieldValue(source, field);
            if (fieldValue == null) {
    
    
                continue;
            }
            boolean noAnnotation = field.getAnnotation(DeepCopy.class) == null;
            if (noAnnotation) {
    
    
                continue;
            }
            if (fieldValue instanceof Collection) {
    
    
                Object newInstance = getInstance(fieldValue, fieldType, newInstanceMap);
                copyCollection((Collection) fieldValue, (Collection) newInstance, newInstanceMap, ignorePropertiesMap);
                ReflectUtil.setFieldValue(target, fieldName, newInstance);
                continue;
            }
            if (fieldValue instanceof Map) {
    
    
                Object newInstance = getInstance(fieldValue, fieldType, newInstanceMap);
                copyMap((Map) fieldValue, (Map) newInstance, newInstanceMap, ignorePropertiesMap);
                ReflectUtil.setFieldValue(target, fieldName, newInstance);
                continue;
            }
            Object newInstance = getInstance(fieldValue, fieldType, newInstanceMap);
            String[] ips = null;
            if (CollUtil.isNotEmpty(ignorePropertiesMap)) {
    
    
                ips = ignorePropertiesMap.get(fieldName);
            }
            BeanUtil.copyProperties(fieldValue, newInstance, ips);
            ReflectUtil.setFieldValue(target, fieldName, newInstance);
            recursion(fieldValue, newInstance, newInstanceMap, ignorePropertiesMap);
        }
    }

    @SuppressWarnings({
    
    "unchecked"})
    private static <T> T getInstance(Object fieldValue, Class<T> fieldType, Map<Type, Object> newInstanceMap) {
    
    
        Object o = null;
        if (CollUtil.isNotEmpty(newInstanceMap)) {
    
    
            o = newInstanceMap.get(fieldType);
        }
        if (o != null) {
    
    
            return (T) o;
        }
        Constructor<?>[] constructors = ReflectUtil.getConstructors(fieldType);
        for (Constructor<?> constructor : constructors) {
    
    
            try {
    
    
                o = constructor.newInstance(fieldValue);
            } catch (Exception ignored) {
    
    
            }
        }
        if (o != null) {
    
    
            return (T) o;
        }
        try {
    
    
            o = ReflectUtil.newInstance(fieldType);
        } catch (UtilException ignored) {
    
    
        }
        if (o != null) {
    
    
            return (T) o;
        }
        if (fieldValue instanceof List) {
    
    
            o = new ArrayList<>();
        }
        if (o != null) {
    
    
            return (T) o;
        }
        if (fieldValue instanceof Set) {
    
    
            o = new HashSet<>();
        }
        if (o != null) {
    
    
            return (T) o;
        }
        if (fieldValue instanceof Map) {
    
    
            o = new HashMap<>();
        }
        if (o != null) {
    
    
            return (T) o;
        }
        throw new UtilException("Instance class [{}] failure!", fieldType);
    }

    @SuppressWarnings({
    
    "unused"})
    private static void copyCollection(Collection<Object> source, Collection<Object> target, Map<Type, Object> newInstanceMap, Map<String, String[]> ignorePropertiesMap) {
    
    
        if (source == null || target == null) {
    
    
            return;
        }
        target.clear();
        for (Object next : source) {
    
    
            Object instance = getInstance(next, next.getClass(), newInstanceMap);
            target.add(instance);
            deepCopyProperties(next, instance, newInstanceMap, ignorePropertiesMap);
        }
    }

    @SuppressWarnings({
    
    "unchecked", "rawtypes", "SameParameterValue"})
    private static void copyMap(Map source, Map target, Map<Type, Object> newInstanceMap, Map<String, String[]> ignorePropertiesMap) {
    
    
        if (source == null || target == null) {
    
    
            return;
        }
        target.clear();
        Set<Map.Entry> sourceEntrySet = source.entrySet();
        for (Map.Entry sourceEntry : sourceEntrySet) {
    
    
            Object key = sourceEntry.getKey();
            Object value = sourceEntry.getValue();
            Object keyInstance = getInstance(key, key.getClass(), newInstanceMap);
            Object valueInstance = getInstance(value, value.getClass(), newInstanceMap);
            deepCopyProperties(key, keyInstance, newInstanceMap, ignorePropertiesMap);
            deepCopyProperties(value, valueInstance, newInstanceMap, ignorePropertiesMap);
            target.put(keyInstance, valueInstance);
        }
    }
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>5.5.4</version>
		</dependency>

猜你喜欢

转载自blog.csdn.net/qq_28807077/article/details/111682944