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

io.github.wj0410.cloudbox.tools.util.reflect.ReflectUtils Maven / Gradle / Ivy

The newest version!
package io.github.wj0410.cloudbox.tools.util.reflect;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
 *
 * @author wangjie
 */
@SuppressWarnings("rawtypes")
public class ReflectUtils {
    private static final String SETTER_PREFIX = "set";

    private static final String GETTER_PREFIX = "get";

    private static final String CGLIB_CLASS_SEPARATOR = "$$";

    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);

    /**
     * 调用Getter方法.
     * 支持多级,如:对象名.对象名.方法
     * @param obj obj
     * @param propertyName propertyName
     * @param  E
     * @return E
     */
    @SuppressWarnings("unchecked")
    public static  E invokeGetter(Object obj, String propertyName) {
        Object object = obj;
        for (String name : StringUtils.split(propertyName, ".")) {
            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
            object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
        }
        return (E) object;
    }

    /**
     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
     * @param obj obj
     * @param fieldName fieldName
     * @param  E
     * @return E
     */
    @SuppressWarnings("unchecked")
    public static  E getFieldValue(final Object obj, final String fieldName) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
            return null;
        }
        E result = null;
        try {
            result = (E) field.get(obj);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常{}", e.getMessage());
        }
        return result;
    }

    /**
     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
     * @param obj obj
     * @param fieldName fieldName
     * @param value value
     * @param  E
     */
    public static  void setFieldValue(final Object obj, final String fieldName, final E value) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
            return;
        }
        try {
            field.set(obj, value);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常: {}", e.getMessage());
        }
    }

    /**
     * 直接调用对象方法, 无视private/protected修饰符.
     * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
     * 同时匹配方法名+参数类型,
     * @param obj obj
     * @param methodName methodName
     * @param parameterTypes parameterTypes
     * @param args args
     * @param  E
     * @return E
     */
    @SuppressWarnings("unchecked")
    public static  E invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes,
                                     final Object[] args) {
        if (obj == null || methodName == null) {
            return null;
        }
        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
        if (method == null) {
            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
            return null;
        }
        try {
            return (E) method.invoke(obj, args);
        } catch (Exception e) {
            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
            throw convertReflectionExceptionToUnchecked(msg, e);
        }
    }


    /**
     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
     * 如向上转型到Object仍无法找到, 返回null.
     * @param obj obj
     * @param fieldName fieldName
     * @return Field
     */
    public static Field getAccessibleField(final Object obj, final String fieldName) {
        // 为空不报错。直接返回 null
        if (obj == null) {
            return null;
        }
        Validate.notBlank(fieldName, "fieldName can't be blank");
        for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                makeAccessible(field);
                return field;
            } catch (NoSuchFieldException e) {
                continue;
            }
        }
        return null;
    }

    /**
     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
     * 如向上转型到Object仍无法找到, 返回null.
     * 匹配函数名+参数类型。
     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
     * @param obj obj
     * @param methodName methodName
     * @param parameterTypes parameterTypes
     * @return Method
     */
    public static Method getAccessibleMethod(final Object obj, final String methodName,
                                             final Class... parameterTypes) {
        // 为空不报错。直接返回 null
        if (obj == null) {
            return null;
        }
        Validate.notBlank(methodName, "methodName can't be blank");
        for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
            try {
                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
                makeAccessible(method);
                return method;
            } catch (NoSuchMethodException e) {
                continue;
            }
        }
        return null;
    }

    /**
     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
     * 如向上转型到Object仍无法找到, 返回null.
     * 只匹配函数名。
     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
     * @param obj obj
     * @param methodName methodName
     * @param argsNum argsNum
     * @return Method
     */
    public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
        // 为空不报错。直接返回 null
        if (obj == null) {
            return null;
        }
        Validate.notBlank(methodName, "methodName can't be blank");
        for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
            Method[] methods = searchType.getDeclaredMethods();
            for (Method method : methods) {
                if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
                    makeAccessible(method);
                    return method;
                }
            }
        }
        return null;
    }

    /**
     * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
     * @param method method
     */
    public static void makeAccessible(Method method) {
        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
                && !method.isAccessible()) {
            method.setAccessible(true);
        }
    }

    /**
     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
     * @param field field
     */
    public static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
                || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }
    }

    /**
     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
     * 如无法找到, 返回Object.class.
     * @param clazz clazz
     * @param  T
     * @return Class
     */
    @SuppressWarnings("unchecked")
    public static  Class getClassGenricType(final Class clazz) {
        return getClassGenricType(clazz, 0);
    }

    /**
     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
     * 如无法找到, 返回Object.class.
     * @param clazz clazz
     * @param index index
     * @return Class
     */
    public static Class getClassGenricType(final Class clazz, final int index) {
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
                    + params.length);
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
            return Object.class;
        }

        return (Class) params[index];
    }

    public static Class getUserClass(Object instance) {
        if (instance == null) {
            throw new RuntimeException("Instance must not be null");
        }
        Class clazz = instance.getClass();
        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
            Class superClass = clazz.getSuperclass();
            if (superClass != null && !Object.class.equals(superClass)) {
                return superClass;
            }
        }
        return clazz;

    }

    /**
     * 将反射时的checked exception转换为unchecked exception.
     * @param msg msg
     * @param e e
     * @return RuntimeException
     */
    public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) {
        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
                || e instanceof NoSuchMethodException) {
            return new IllegalArgumentException(msg, e);
        } else if (e instanceof InvocationTargetException) {
            return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
        }
        return new RuntimeException(msg, e);
    }
    // 缓存对象的类和方法
    private static final Map, Map> classMethodCache = new ConcurrentHashMap<>();
    private static final Map, List> classFieldsCache = new ConcurrentHashMap<>();

    public static List getFieldsFromCache(Object obj) {
        Class clazz = obj.getClass();
        List fields = classFieldsCache.get(clazz);
        if (CollectionUtils.isEmpty(fields)) {
            fields = new ArrayList<>();
            getFields(clazz, fields);
            classFieldsCache.put(clazz, fields);
        }
        return fields;
    }

    // 从缓存中获取对象的类和方法,如果不存在就反射获取并保存到缓存中
    public static Method getMethodFromCache(Object obj, String methodName, Class type) {
        // 获取对象的类
        Class cls = obj.getClass();
        // 从缓存中获取对象类对应的方法Map
        Map methodMap = classMethodCache.get(cls);
        // 如果方法Map为空
        if (methodMap == null) {
            // 创建一个新的方法Map
            methodMap = new ConcurrentHashMap<>();
            // 将对象类和方法Map放入缓存中
            classMethodCache.put(cls, methodMap);
        }
        // 从方法Map中获取指定名称和类型的方法
        Method method = methodMap.get(methodName);
        // 如果方法为空
        if (method == null) {
            try {
                // 反射获取指定名称和类型的方法
                method = cls.getMethod(methodName, type);
                // 将方法放入方法Map中
                methodMap.put(methodName, method);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        // 返回方法
        return method;
    }

    /**
     * 给对象的属性赋值 局限性
     * 如果对象的属性名和set方法名不一致,比如属性名是name,set方法名是setNameWithPrefix,那么这种方法就无法获取到正确的方法。
     * 如果对象的属性有重载的set方法,比如有setAge(int age)和setAge(String age),那么这种方法就无法确定要获取哪个方法。
     * 如果对象的属性没有对应的set方法,比如是final或者常量,那么这种方法就无法赋值。
     *
     * @param propertyName 属性名
     * @param value        值
     * @param obj          对象
     */
    public static void assignValueToObjectPropertyByField(String propertyName, Object value, Object obj) {
        // 获取对象的类
        Class cls = obj.getClass();
        // 拼接set方法名
        String methodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        try {
            // 尝试从缓存中获取set方法
            Method method = getMethodFromCache(obj, methodName, value.getClass());
            // 如果存在,就调用set方法赋值
            if (method != null) {
                method.invoke(obj, value);
            } else {
                // 如果不存在,就尝试用反射获取属性
                Field field = cls.getDeclaredField(propertyName);
                // 如果存在,就直接用反射赋值
                if (field != null) {
                    field.setAccessible(true); // 设置可访问私有属性
                    field.set(obj, value); // 赋值
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通用方法
     * 给对象的属性赋值
     *
     * @param propertyName 属性名
     * @param value        值
     * @param obj          对象
     */
    public static void assignValueToObjectPropertyByMethod(String propertyName, Object value, Object obj) {
        // 获取对象的类
        Class cls = obj.getClass();
        // 获取对象的所有属性
        Field[] fields = cls.getDeclaredFields();
        // 遍历属性数组
        for (Field field : fields) {
            // 如果属性名和参数一致
            if (field.getName().equals(propertyName)) {
                // 获取属性的类型
                Class type = field.getType();
                // 拼接set方法名
                String methodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                try {
                    // 尝试从缓存中获取set方法
                    Method method = getMethodFromCache(obj, methodName, type);
                    // 如果存在,就调用set方法赋值
                    if (method != null) {
                        method.invoke(obj, value);
                    } else {
                        // 如果不存在,就直接用反射赋值
                        field.setAccessible(true); // 设置可访问私有属性
                        field.set(obj, value); // 赋值
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                break; // 跳出循环
            }
        }
    }

    /**
     * 获取属性的名字
     * 属性必须有 get 或者 is 方法
     * @param func func
     * @param  T
     * @return String
     */
    public static  String getFieldName(PropertyFunc func) {
        try {
            // 通过获取对象方法,判断是否存在该方法
            Method method = func.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            // 利用jdk的SerializedLambda 解析方法引用
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(func);
            String getter = serializedLambda.getImplMethodName();
            return resolveFieldName(getter);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    public static  String getFiledValue(PropertyFunc func, T obj) {
        try {
            // 通过获取对象方法,判断是否存在该方法
            Method method = func.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            // 利用jdk的SerializedLambda 解析方法引用
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(func);
            String getter = serializedLambda.getImplMethodName();
            Class clazz = ClassLoader.getSystemClassLoader().loadClass(serializedLambda.getImplClass().replace("/", "."));
            Method m = clazz.getMethod(getter);
            return String.valueOf(m.invoke(obj));
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 有局限性,通过默认的get方法获取
     * @param filedName filedName
     * @param obj obj
     * @param  T
     * @return String
     */
    public static  String getFiledValue(String filedName, T obj) {
        try {
            // 通过获取对象方法,判断是否存在该方法
            Method method = obj.getClass().getMethod("get" + captureName(filedName));
            return String.valueOf(method.invoke(obj));
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    private static String resolveFieldName(String getMethodName) {
        if (getMethodName.startsWith("get")) {
            getMethodName = getMethodName.substring(3);
        } else if (getMethodName.startsWith("is")) {
            getMethodName = getMethodName.substring(2);
        }
        // 小写第一个字母
        return firstToLowerCase(getMethodName);
    }

    private static String firstToLowerCase(String param) {
        if (io.github.wj0410.cloudbox.tools.util.StringUtils.isBlank(param)) {
            return "";
        }
        return param.substring(0, 1).toLowerCase() + param.substring(1);
    }

    /**
     * 获取类的所有属性,递归查询继承类
     * @param clazz
     * @param fields
     * @return
     */
    private static List getFields(Class clazz, List fields) {
        Class superclass = clazz.getSuperclass();
        if (superclass != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            getFields(superclass, fields);
        } else {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        }
        return fields;
    }

    /**
     * 将字符串的首字母转大写
     *
     * @param str 需要转换的字符串
     * @return String
     */
    private static String captureName(String str) {
        // 进行字母的ascii编码前移,效率要高于截取字符串进行转换的操作
        char[] cs = str.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy