import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Vo接口
 * @param <E> 实体类型
 * @param <V> VO类型
 */
public interface Vo<E, V> {

    /**
     * 转换为实体类型对象
     * @return 实体类型对象
     */
    default E to() {
        Type entityType =getActualTypeArguments()[0];
        if (entityType instanceof Class<?> entityClass) {
            return (E) copyProperties(this, entityClass);
        }
        throw new RuntimeException("Vo接口泛型参数错误");
    }

    /**
     * 从实体类型对象中创建VO对象
     * @param entity 实体类型对象
     * @param voClass VO类型
     * @return VO对象
     * @param <E> 实体类型
     * @param <V> VO类型
     */
    static <E, V> V from(E entity, Class<V> voClass) {
        return copyProperties(entity, voClass);
    }

    private Type[] getActualTypeArguments() {
        ParameterizedType voType = getParameterizedType();
        Type[] arguments = voType.getActualTypeArguments();
        if (arguments.length != 2) {
            throw new RuntimeException("Vo接口泛型参数错误");
        }
        return arguments;
    }

    private ParameterizedType getParameterizedType() {
        Type[] types = getClass().getGenericInterfaces();
        ParameterizedType voType = null;
        for (Type type : types) {
            if (type instanceof ParameterizedType parameterizedType) {
                String typeName = parameterizedType.getRawType().getTypeName();
                if (typeName.equals(Vo.class.getName())) {
                    voType = parameterizedType;
                }
            }
        }
        if (voType == null) {
            throw new RuntimeException("Vo接口未实现");
        }
        return voType;
    }

    private static <T> T copyProperties(Object source, Class<T> targetClass) {

        T target;
        try {
            target = targetClass.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        Map<String, Field> voFieldMap = Arrays.stream(source.getClass().getDeclaredFields()).collect(Collectors.toMap(Field::getName, v -> v));
        for (Field field : targetClass.getDeclaredFields()) {
            if (voFieldMap.containsKey(field.getName())) {
                field.setAccessible(true);
                voFieldMap.get(field.getName()).setAccessible(true);
                try {
                    field.set(target, voFieldMap.get(field.getName()).get(source));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return target;
    }

}

评论已关闭