ReflectUtils.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. package com.ruoyi.common.utils.reflect;
  2. import com.ruoyi.common.core.text.Convert;
  3. import com.ruoyi.common.utils.DateUtils;
  4. import org.apache.commons.lang3.StringUtils;
  5. import org.apache.commons.lang3.Validate;
  6. import org.apache.poi.ss.usermodel.DateUtil;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import java.lang.reflect.*;
  10. import java.util.Date;
  11. /**
  12. * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
  13. *
  14. * @author ruoyi
  15. */
  16. @SuppressWarnings("rawtypes")
  17. public class ReflectUtils {
  18. private static final String SETTER_PREFIX = "set";
  19. private static final String GETTER_PREFIX = "get";
  20. private static final String CGLIB_CLASS_SEPARATOR = "$$";
  21. private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
  22. /**
  23. * 调用Getter方法.
  24. * 支持多级,如:对象名.对象名.方法
  25. */
  26. @SuppressWarnings("unchecked")
  27. public static <E> E invokeGetter(Object obj, String propertyName) {
  28. Object object = obj;
  29. for (String name : StringUtils.split(propertyName, ".")) {
  30. String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
  31. object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
  32. }
  33. return (E) object;
  34. }
  35. /**
  36. * 调用Setter方法, 仅匹配方法名。
  37. * 支持多级,如:对象名.对象名.方法
  38. */
  39. public static <E> void invokeSetter(Object obj, String propertyName, E value) {
  40. Object object = obj;
  41. String[] names = StringUtils.split(propertyName, ".");
  42. for (int i = 0; i < names.length; i++) {
  43. if (i < names.length - 1) {
  44. String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
  45. object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
  46. } else {
  47. String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
  48. invokeMethodByName(object, setterMethodName, new Object[]{value});
  49. }
  50. }
  51. }
  52. /**
  53. * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
  54. */
  55. @SuppressWarnings("unchecked")
  56. public static <E> E getFieldValue(final Object obj, final String fieldName) {
  57. Field field = getAccessibleField(obj, fieldName);
  58. if (field == null) {
  59. logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
  60. return null;
  61. }
  62. E result = null;
  63. try {
  64. result = (E) field.get(obj);
  65. } catch (IllegalAccessException e) {
  66. logger.error("不可能抛出的异常{}", e.getMessage());
  67. }
  68. return result;
  69. }
  70. /**
  71. * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
  72. */
  73. public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) {
  74. Field field = getAccessibleField(obj, fieldName);
  75. if (field == null) {
  76. // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
  77. logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
  78. return;
  79. }
  80. try {
  81. field.set(obj, value);
  82. } catch (IllegalAccessException e) {
  83. logger.error("不可能抛出的异常: {}", e.getMessage());
  84. }
  85. }
  86. /**
  87. * 直接调用对象方法, 无视private/protected修饰符.
  88. * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
  89. * 同时匹配方法名+参数类型,
  90. */
  91. @SuppressWarnings("unchecked")
  92. public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
  93. final Object[] args) {
  94. if (obj == null || methodName == null) {
  95. return null;
  96. }
  97. Method method = getAccessibleMethod(obj, methodName, parameterTypes);
  98. if (method == null) {
  99. logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
  100. return null;
  101. }
  102. try {
  103. return (E) method.invoke(obj, args);
  104. } catch (Exception e) {
  105. String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
  106. throw convertReflectionExceptionToUnchecked(msg, e);
  107. }
  108. }
  109. /**
  110. * 直接调用对象方法, 无视private/protected修饰符,
  111. * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
  112. * 只匹配函数名,如果有多个同名函数调用第一个。
  113. */
  114. @SuppressWarnings("unchecked")
  115. public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
  116. Method method = getAccessibleMethodByName(obj, methodName, args.length);
  117. if (method == null) {
  118. // 如果为空不报错,直接返回空。
  119. logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
  120. return null;
  121. }
  122. try {
  123. // 类型转换(将参数数据类型转换为目标方法参数类型)
  124. Class<?>[] cs = method.getParameterTypes();
  125. for (int i = 0; i < cs.length; i++) {
  126. if (args[i] != null && !args[i].getClass().equals(cs[i])) {
  127. if (cs[i] == String.class) {
  128. args[i] = Convert.toStr(args[i]);
  129. if (StringUtils.endsWith((String) args[i], ".0")) {
  130. args[i] = StringUtils.substringBefore((String) args[i], ".0");
  131. }
  132. } else if (cs[i] == Integer.class) {
  133. args[i] = Convert.toInt(args[i]);
  134. } else if (cs[i] == Long.class) {
  135. args[i] = Convert.toLong(args[i]);
  136. } else if (cs[i] == Double.class) {
  137. args[i] = Convert.toDouble(args[i]);
  138. } else if (cs[i] == Float.class) {
  139. args[i] = Convert.toFloat(args[i]);
  140. } else if (cs[i] == Date.class) {
  141. if (args[i] instanceof String) {
  142. args[i] = DateUtils.parseDate(args[i]);
  143. } else {
  144. args[i] = DateUtil.getJavaDate((Double) args[i]);
  145. }
  146. } else if (cs[i] == boolean.class || cs[i] == Boolean.class) {
  147. args[i] = Convert.toBool(args[i]);
  148. }
  149. }
  150. }
  151. return (E) method.invoke(obj, args);
  152. } catch (Exception e) {
  153. String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
  154. throw convertReflectionExceptionToUnchecked(msg, e);
  155. }
  156. }
  157. /**
  158. * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
  159. * 如向上转型到Object仍无法找到, 返回null.
  160. */
  161. public static Field getAccessibleField(final Object obj, final String fieldName) {
  162. // 为空不报错。直接返回 null
  163. if (obj == null) {
  164. return null;
  165. }
  166. Validate.notBlank(fieldName, "fieldName can't be blank");
  167. for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
  168. try {
  169. Field field = superClass.getDeclaredField(fieldName);
  170. makeAccessible(field);
  171. return field;
  172. } catch (NoSuchFieldException e) {
  173. continue;
  174. }
  175. }
  176. return null;
  177. }
  178. /**
  179. * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
  180. * 如向上转型到Object仍无法找到, 返回null.
  181. * 匹配函数名+参数类型。
  182. * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
  183. */
  184. public static Method getAccessibleMethod(final Object obj, final String methodName,
  185. final Class<?>... parameterTypes) {
  186. // 为空不报错。直接返回 null
  187. if (obj == null) {
  188. return null;
  189. }
  190. Validate.notBlank(methodName, "methodName can't be blank");
  191. for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
  192. try {
  193. Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
  194. makeAccessible(method);
  195. return method;
  196. } catch (NoSuchMethodException e) {
  197. continue;
  198. }
  199. }
  200. return null;
  201. }
  202. /**
  203. * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
  204. * 如向上转型到Object仍无法找到, 返回null.
  205. * 只匹配函数名。
  206. * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
  207. */
  208. public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
  209. // 为空不报错。直接返回 null
  210. if (obj == null) {
  211. return null;
  212. }
  213. Validate.notBlank(methodName, "methodName can't be blank");
  214. for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
  215. Method[] methods = searchType.getDeclaredMethods();
  216. for (Method method : methods) {
  217. if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
  218. makeAccessible(method);
  219. return method;
  220. }
  221. }
  222. }
  223. return null;
  224. }
  225. /**
  226. * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
  227. */
  228. public static void makeAccessible(Method method) {
  229. if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
  230. && !method.isAccessible()) {
  231. method.setAccessible(true);
  232. }
  233. }
  234. /**
  235. * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
  236. */
  237. public static void makeAccessible(Field field) {
  238. if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
  239. || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
  240. field.setAccessible(true);
  241. }
  242. }
  243. /**
  244. * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
  245. * 如无法找到, 返回Object.class.
  246. */
  247. @SuppressWarnings("unchecked")
  248. public static <T> Class<T> getClassGenricType(final Class clazz) {
  249. return getClassGenricType(clazz, 0);
  250. }
  251. /**
  252. * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
  253. * 如无法找到, 返回Object.class.
  254. */
  255. public static Class getClassGenricType(final Class clazz, final int index) {
  256. Type genType = clazz.getGenericSuperclass();
  257. if (!(genType instanceof ParameterizedType)) {
  258. logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
  259. return Object.class;
  260. }
  261. Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
  262. if (index >= params.length || index < 0) {
  263. logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
  264. + params.length);
  265. return Object.class;
  266. }
  267. if (!(params[index] instanceof Class)) {
  268. logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
  269. return Object.class;
  270. }
  271. return (Class) params[index];
  272. }
  273. public static Class<?> getUserClass(Object instance) {
  274. if (instance == null) {
  275. throw new RuntimeException("Instance must not be null");
  276. }
  277. Class clazz = instance.getClass();
  278. if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
  279. Class<?> superClass = clazz.getSuperclass();
  280. if (superClass != null && !Object.class.equals(superClass)) {
  281. return superClass;
  282. }
  283. }
  284. return clazz;
  285. }
  286. /**
  287. * 将反射时的checked exception转换为unchecked exception.
  288. */
  289. public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) {
  290. if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
  291. || e instanceof NoSuchMethodException) {
  292. return new IllegalArgumentException(msg, e);
  293. } else if (e instanceof InvocationTargetException) {
  294. return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
  295. }
  296. return new RuntimeException(msg, e);
  297. }
  298. }