package com.younike.common.utils.copy;


import java.lang.reflect.Field;
import java.lang.reflect.Method;


/**
 * 对象拷贝工具类
 * 2021-7-15
 */
public class CopyUtils {

    /**
     * 将一个集合中对象的值拷贝到另一个对象，属性相同即赋值
     * @param tClass 源数据，将此对象数据取出
     * @param eClass 目标对象，将取出的数据赋值到该对象中
     * @param <T> 源数据类型
     * @param <E> 目标数据类型
     * @return 被赋值后的目标对象集合
     */
    public static <T, E> Class<E> copyProperties(Class<T> tClass, Class<E> eClass) throws Exception {

        // 获取源对象的所有属性
        Field[] tFields = tClass.getDeclaredFields();
        // 获取目标对象的所有属性
        Field[] eFields = eClass.getDeclaredFields();

        E target;
        try {
            // 通过类的详情信息，创建目标对象 这一步等同于UserTwo target = new UserTwo()；
            target = eClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("目标对象创建失败");
        }

        // 循环取到源对象的单个属性
        for(Field tField : tFields) {
            // 循环取到目标对象的单个属性
            for(Field eField : eFields) {

                // 判断源对象的属性名、属性类型是否和目标对象的属性名、属性类型一致
                if(tField.getName().equals(eField.getName()) && tField.getGenericType().equals(eField.getGenericType())) {

                    try {
                        // 获取源对象的属性名，将属性名首字母大写，拼接如：getUsername、getId的字符串
                        String tName = tField.getName();
                        char[] tChars = tName.toCharArray();
                        tChars[0] -= 32;
                        String tMethodName = "get" + String.valueOf(tChars);
                        // 获得属性的get方法
                        Method tMethod = tClass.getMethod(tMethodName);
                        // 调用get方法
                        Object tFieldValue = tMethod.invoke(tClass);

                        // 获取目标对象的属性名，将属性名首字母大写，拼接如：setUsername、setId的字符串
                        String eName = eField.getName();
                        char[] eChars = eName.toCharArray();
                        tChars[0] -= 32;
                        String eMethodName = "set" + String.valueOf(eChars);
                        // 获得属性的set方法
                        Method eMethod = tClass.getMethod(eMethodName, eField.getType());
                        // 调用方法，并将源对象get方法返回值作为参数传入
                        eMethod.invoke(target, tFieldValue);

                        break;
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new Exception("转换失败，请检查属性类型是否匹配");
                    }
                }
            }
        }
        return (Class<E>) target;
    }

}
