All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.liuyehcf.framework.rpc.maple.util.JavaBeanInitializer Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
package com.github.liuyehcf.framework.rpc.maple.util;

import java.lang.reflect.*;
import java.util.*;

public class JavaBeanInitializer {
    private static final Byte BYTE_DEFAULT_VALUE = 1;
    private static final Character CHAR_DEFAULT_VALUE = 'a';
    private static final Short SHORT_DEFAULT_VALUE = 2;
    private static final Integer INTEGER_DEFAULT_VALUE = 3;
    private static final Long LONG_DEFAULT_VALUE = 6L;
    private static final Float FLOAT_DEFAULT_VALUE = 1.0F;
    private static final Double DOUBLE_DEFAULT_VALUE = 2.0D;
    private static final String STRING_DEFAULT_VALUE = "default";

    private static final Map DEFAULT_VALUE_OF_BASIC_CLASS = new HashMap<>();

    private static final String SET_METHOD_PREFIX = "set";
    private static final Integer SET_METHOD_PARAM_COUNT = 1;
    private static final Class SET_METHOD_RETURN_TYPE = void.class;

    private static final Set CONTAINER_CLASS_SET = new HashSet<>();
    private static final Integer CONTAINER_DEFAULT_SIZE = 3;

    static {
        DEFAULT_VALUE_OF_BASIC_CLASS.put(Byte.class, BYTE_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(byte.class, BYTE_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Character.class, CHAR_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(char.class, CHAR_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Short.class, SHORT_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(short.class, SHORT_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Integer.class, INTEGER_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(int.class, INTEGER_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Long.class, LONG_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(long.class, LONG_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Float.class, FLOAT_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(float.class, FLOAT_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Double.class, DOUBLE_DEFAULT_VALUE);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(double.class, DOUBLE_DEFAULT_VALUE);

        DEFAULT_VALUE_OF_BASIC_CLASS.put(Boolean.class, false);
        DEFAULT_VALUE_OF_BASIC_CLASS.put(boolean.class, false);
    }

    static {
        CONTAINER_CLASS_SET.add(List.class);
        CONTAINER_CLASS_SET.add(Map.class);
        CONTAINER_CLASS_SET.add(Set.class);
        CONTAINER_CLASS_SET.add(Queue.class);
    }

    /**
     * 要初始化的类型
     */
    private final Type type;
    /**
     * 从泛型参数名映射到实际的类型
     */
    private Map genericTypes;

    private JavaBeanInitializer(Type type, Map superClassGenericTypes) {
        this.type = type;
        genericTypes = new HashMap<>();
        init(superClassGenericTypes);
    }

    /**
     * 唯一对外接口
     */
    @SuppressWarnings("unchecked")
    public static  T createJavaBean(TypeReference typeReference) {
        if (typeReference == null) {
            throw new NullPointerException();
        }
        return (T) createJavaBean(typeReference.getType(), null, null);
    }

    /**
     * 初始化JavaBean
     */
    private static Object createJavaBean(Type type, Map superClassGenericTypes, Type superType) {
        if (type == null) {
            throw new NullPointerException();
        }
        // 如果一个DTO嵌套了自己,避免死循环
        if (type.equals(superType)) {
            return null;
        }
        return new JavaBeanInitializer(type, superClassGenericTypes)
                .doCreateJavaBean();
    }

    /**
     * 对于泛型类型,初始化泛型参数描述与实际泛型参数的映射关系
     * 例如List有一个泛型参数T,如果传入的是List类型,那么建立 "T"->java.lang.String 的映射
     */
    private void init(Map superClassGenericTypes) {
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;

            Class clazz = (Class) parameterizedType.getRawType();

            // 通过Class可以拿到泛型形参,但无法拿到泛型实参
            TypeVariable[] typeVariables = clazz.getTypeParameters();

            // 通过ParameterizedType可以拿到泛型实参,通过继承结构保留泛型实参
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (int i = 0; i < actualTypeArguments.length; i++) {
                Type actualTypeArgument = actualTypeArguments[i];
                if (actualTypeArgument instanceof TypeVariable) {
                    if (superClassGenericTypes == null
                            || (actualTypeArgument = superClassGenericTypes.get(getNameOfTypeVariable(actualTypeArgument))) == null) {
                        throw new RuntimeException();
                    }
                    actualTypeArguments[i] = actualTypeArgument;
                }
            }

            // 维护泛型形参到泛型实参的映射关系
            for (int i = 0; i < typeVariables.length; i++) {
                genericTypes.put(
                        // 这里需要拼接一下,使得泛型形参有一个命名空间的保护,否则泛型形参可能会出现覆盖的情况
                        getNameOfTypeVariable(typeVariables[i]),
                        actualTypeArguments[i]
                );
            }
        }
    }

    private String getNameOfTypeVariable(Type typeVariable) {
        return ((TypeVariable) typeVariable).getName();
    }

    /**
     * 创建JavaBean,根据type的实际类型进行分发
     */
    private Object doCreateJavaBean() {
        if (type instanceof Class) {
            // 创建非泛型实例
            return createJavaBeanWithClass((Class) type);
        } else if (type instanceof ParameterizedType) {
            // 创建泛型实例
            return createJavaBeanWithGenericType((ParameterizedType) type);
        } else {
            throw new UnsupportedOperationException("暂不支持此类型的默认初始化,type: " + type);
        }
    }

    /**
     * 通过普通的Class创建JavaBean
     */
    private Object createJavaBeanWithClass(Class clazz) {

        if (DEFAULT_VALUE_OF_BASIC_CLASS.containsKey(clazz)) {
            return DEFAULT_VALUE_OF_BASIC_CLASS.get(clazz);
        } else if (String.class.equals(clazz)) {
            return STRING_DEFAULT_VALUE;
        }

        Object obj = createInstance(clazz);

        for (Method setMethod : getSetMethods(clazz)) {

            // 拿到set方法的参数类型
            Type paramType = setMethod.getGenericParameterTypes()[0];

            // 填充默认值
            setDefaultValue(obj, setMethod, paramType);
        }

        return obj;
    }

    /**
     * 通过带有泛型实参的ParameterizedType创建JavaBean
     */
    private Object createJavaBeanWithGenericType(ParameterizedType type) {

        Class clazz = (Class) type.getRawType();

        Object obj = createInstance(clazz);

        for (Method setMethod : getSetMethods(clazz)) {
            // 拿到set方法的参数类型
            Type paramType = setMethod.getGenericParameterTypes()[0];

            if (paramType instanceof TypeVariable) {
                // 如果参数类型是泛型形参,根据映射关系找到泛型形参对应的泛型实参
                Type actualType = genericTypes.get(getNameOfTypeVariable(paramType));
                setDefaultValue(obj, setMethod, actualType);
            } else {
                // 参数类型是确切的类型,可能是Class,也可能是ParameterizedType
                setDefaultValue(obj, setMethod, paramType);
            }
        }

        return obj;
    }

    /**
     * 通过反射创建实例
     */
    private Object createInstance(Class clazz) {
        Object obj;
        try {
            obj = clazz.newInstance();
        } catch (IllegalAccessException | InstantiationException e) {
            throw new RuntimeException("不能实例化接口/抽象类/没有无参构造方法的类");
        }
        return obj;
    }

    /**
     * 返回所有set方法
     */
    private List getSetMethods(Class clazz) {
        List setMethods = new ArrayList<>();
        Method[] methods = clazz.getMethods();

        for (Method method : methods) {
            if (method.getName().startsWith(SET_METHOD_PREFIX)
                    && SET_METHOD_PARAM_COUNT.equals(method.getParameterCount())
                    && SET_METHOD_RETURN_TYPE.equals(method.getReturnType())) {
                setMethods.add(method);
            }
        }
        return setMethods;
    }

    /**
     * 为属性设置默认值,根据参数类型进行分发
     */
    private void setDefaultValue(Object obj, Method method, Type paramType) {
        try {
            if (paramType instanceof Class) {
                // 普通参数
                setDefaultValueOfNormal(obj, method, (Class) paramType);
            } else if (paramType instanceof ParameterizedType) {
                // 泛型实参
                setDefaultValueOfGeneric(obj, method, (ParameterizedType) paramType);
            } else {
                throw new UnsupportedOperationException();
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException();
        }
    }

    /**
     * 获取属性名
     */
    private String getFieldName(Method method) {
        return method.getName().substring(3);
    }

    /**
     * set方法参数是普通的类型
     */
    private void setDefaultValueOfNormal(Object obj, Method method, Class paramClass) throws IllegalAccessException, InvocationTargetException {
        if (DEFAULT_VALUE_OF_BASIC_CLASS.containsKey(paramClass)) {
            // 填充基本类型
            method.invoke(obj, DEFAULT_VALUE_OF_BASIC_CLASS.get(paramClass));
        } else if (String.class.equals(paramClass)) {
            // 填充String类型
            method.invoke(obj, STRING_DEFAULT_VALUE + getFieldName(method));
        } else {
            // 填充其他类型
            method.invoke(obj, createJavaBean(paramClass, genericTypes, type));
        }
    }

    /**
     * set方法的参数是泛型
     */
    private void setDefaultValueOfGeneric(Object obj, Method method, ParameterizedType paramType) throws IllegalAccessException, InvocationTargetException {
        Class clazz = (Class) paramType.getRawType();

        if (instanceOfContainer(clazz)) {
            // 如果是容器的话,特殊处理一下
            setDefaultValueForContainer(obj, method, paramType);
        } else {
            // 其他类型
            method.invoke(obj, createJavaBean(paramType, genericTypes, type));
        }
    }

    /**
     * 判断是否是容器类型
     */
    private boolean instanceOfContainer(Class clazz) {
        return CONTAINER_CLASS_SET.contains(clazz);
    }

    /**
     * 为几种不同的容器设置默认值,由于容器没有set方法,走默认逻辑就会得到一个空的容器。因此为容器填充一个值
     */
    @SuppressWarnings("unchecked")
    private void setDefaultValueForContainer(Object obj, Method method, ParameterizedType paramType) throws IllegalAccessException, InvocationTargetException {
        Class clazz = (Class) paramType.getRawType();

        if (List.class.equals(clazz)) {
            List list = new ArrayList();

            Type genericParam = paramType.getActualTypeArguments()[0];

            for (int i = 0; i < CONTAINER_DEFAULT_SIZE; i++) {
                list.add(createJavaBeanWithTypeVariable(genericParam));
            }

            method.invoke(obj, list);
        } else if (Set.class.equals(clazz)) {
            Set set = new HashSet();

            Type genericParam = paramType.getActualTypeArguments()[0];

            for (int i = 0; i < CONTAINER_DEFAULT_SIZE; i++) {
                set.add(createJavaBeanWithTypeVariable(genericParam));
            }

            method.invoke(obj, set);
        } else if (Queue.class.equals(clazz)) {
            Queue queue = new LinkedList();

            Type genericParam = paramType.getActualTypeArguments()[0];

            for (int i = 0; i < CONTAINER_DEFAULT_SIZE; i++) {
                queue.add(createJavaBeanWithTypeVariable(genericParam));
            }

            method.invoke(obj, queue);
        } else if (Map.class.equals(clazz)) {
            Map map = new HashMap();

            Type genericParam1 = paramType.getActualTypeArguments()[0];
            Type genericParam2 = paramType.getActualTypeArguments()[1];

            Object key;
            Object value;

            for (int i = 0; i < CONTAINER_DEFAULT_SIZE; i++) {
                key = createJavaBeanWithTypeVariable(genericParam1);
                value = createJavaBeanWithTypeVariable(genericParam2);

                map.put(key, value);
            }

            method.invoke(obj, map);
        } else {
            throw new UnsupportedOperationException();
        }
    }

    private Object createJavaBeanWithTypeVariable(Type type) {
        if (type instanceof TypeVariable) {
            return createJavaBean(genericTypes.get(getNameOfTypeVariable(type)), genericTypes, this.type);
        } else {
            return createJavaBean(type, genericTypes, this.type);
        }
    }

    public static abstract class TypeReference {
        private final Type type;

        protected TypeReference() {
            Type superClass = getClass().getGenericSuperclass();

            Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];

            this.type = type;
        }

        public final Type getType() {
            return type;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy