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