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

com.github.stupdit1t.jackson.expand.util.ReflectUtil Maven / Gradle / Ivy

The newest version!
package com.github.stupdit1t.jackson.expand.util;

import org.springframework.util.ObjectUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ReflectUtil {

    /**
     * 包装类型为Key,原始类型为Value,例如: Integer.class =》 int.class.
     */
    public static final Map, Class> WRAPPER_PRIMITIVE_MAP = new ConcurrentHashMap<>(8);

    static {
        WRAPPER_PRIMITIVE_MAP.put(Boolean.class, boolean.class);
        WRAPPER_PRIMITIVE_MAP.put(Byte.class, byte.class);
        WRAPPER_PRIMITIVE_MAP.put(Character.class, char.class);
        WRAPPER_PRIMITIVE_MAP.put(Double.class, double.class);
        WRAPPER_PRIMITIVE_MAP.put(Float.class, float.class);
        WRAPPER_PRIMITIVE_MAP.put(Integer.class, int.class);
        WRAPPER_PRIMITIVE_MAP.put(Long.class, long.class);
        WRAPPER_PRIMITIVE_MAP.put(Short.class, short.class);
    }

    /**
     * 反射方法缓存
     */
    private static final Map METHODS_CACHE = new ConcurrentHashMap<>();

    /**
     * 反射调用
     *
     * @param obj
     * @param methodName
     * @param args
     * @return
     */
    public static Object invoke(Object obj, String methodName, Object[] args) throws InvocationTargetException, IllegalAccessException {
        String cacheKey = obj.getClass().getName() + methodName;
        final Method method = METHODS_CACHE.computeIfAbsent(cacheKey, (key) -> getMethod(obj.getClass(), methodName, args));
        if (null == method) {
            throw new UnsupportedOperationException("No such method: [" + methodName + "] from [" + obj.getClass() + "]");
        }
        return method.invoke(obj, args);
    }

    /**
     * 获取反射方法
     *
     * @param beanClass
     * @param methodName
     * @param args
     * @return
     */
    private static Method getMethod(Class beanClass, String methodName, Object[] args) {
        List allMethods = new ArrayList<>();
        Class searchType = beanClass;
        Class[] argsClasses = getClasses(args);
        while (searchType != null) {
            allMethods.addAll(new ArrayList<>(Arrays.asList(searchType.getDeclaredMethods())));
            searchType = searchType.getSuperclass();
        }

        for (Method method : allMethods) {
            if (methodName.equals(method.getName()) && isAllAssignableFrom(method.getParameterTypes(), argsClasses)
                    //排除桥接方法
                    && !method.isBridge()) {
                return method;
            }
        }

        return null;
    }

    /**
     * 获得对象数组的类数组
     *
     * @param objects 对象数组,如果数组中存在{@code null}元素,则此元素被认为是Object类型
     * @return 类数组
     */
    public static Class[] getClasses(Object... objects) {
        Class[] classes = new Class[objects.length];
        Object obj;
        for (int i = 0; i < objects.length; i++) {
            obj = objects[i];
            if (null == obj) {
                classes[i] = Object.class;
            } else {
                classes[i] = obj.getClass();
            }
        }
        return classes;
    }

    /**
     * 比较判断types1和types2两组类,如果types1中所有的类都与types2对应位置的类相同,或者是其父类或接口,则返回{@code true}
     *
     * @param types1 类组1
     * @param types2 类组2
     * @return 是否相同、父类或接口
     */
    private static boolean isAllAssignableFrom(Class[] types1, Class[] types2) {
        if (ObjectUtils.isEmpty(types1) && ObjectUtils.isEmpty(types2)) {
            return true;
        }
        if (null == types1 || null == types2) {
            // 任何一个为null不相等(之前已判断两个都为null的情况)
            return false;
        }
        if (types1.length != types2.length) {
            return false;
        }

        Class type1;
        Class type2;
        for (int i = 0; i < types1.length; i++) {
            type1 = types1[i];
            type2 = types2[i];
            if (isBasicType(type1) && isBasicType(type2)) {
                // 原始类型和包装类型存在不一致情况
                if (unWrap(type1) != unWrap(type2)) {
                    return false;
                }
            } else if (!type1.isAssignableFrom(type2)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 是否为基本类型(包括包装类和原始类)
     *
     * @param clazz 类
     * @return 是否为基本类型
     */
    private static boolean isBasicType(Class clazz) {
        if (null == clazz) {
            return false;
        }
        return (clazz.isPrimitive() || WRAPPER_PRIMITIVE_MAP.containsKey(clazz));
    }

    /**
     * 包装类转为原始类,非包装类返回原类
     *
     * @param clazz 包装类
     * @return 原始类
     */
    private static Class unWrap(Class clazz) {
        if (null == clazz || clazz.isPrimitive()) {
            return clazz;
        }
        Class result = WRAPPER_PRIMITIVE_MAP.get(clazz);
        return (null == result) ? clazz : result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy