content: package org.superboot.utils;
  
  import java.lang.reflect.*;
  
  /**
   * <b> 类映射工具 </b>
   * <p>
   * 功能描述:提供基于类名、方法、字段的映射与解析
   * </p>
   */
  public class ReflectionUtils {
  
      private static final String SETTER_PREFIX = "set";
  
      private static final String GETTER_PREFIX = "get";
  
  
      /**
       * 直接调用对象方法, 无视private/protected修饰符，
       * 用于一次性调用的情况，否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
       * 只匹配函数名，如果有多个同名函数调用第一个。
       */
      public static Object invokeMethod(final Object obj, final String methodName, final Object[] args) {
          Method method = getAccessibleMethod(obj, methodName);
          if (method == null) {
              throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
          }
  
          try {
              return method.invoke(obj, args);
          } catch (Exception e) {
              throw convertReflectionExceptionToUnchecked(e);
          }
      }
  
      /**
       * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
       * <p>
       * 如向上转型到Object仍无法找到, 返回null.
       *
       * @param obj       类名称
       * @param fieldName 字段名称
       * @return
       */
      public static Field getAccessibleField(final Object obj, final String fieldName) {
          for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
              try {
                  Field field = superClass.getDeclaredField(fieldName);
                  makeAccessible(field);
                  return field;
              } catch (NoSuchFieldException e) {//NOSONAR
                  // Field不在当前类定义,继续向上转型
                  continue;// new add
              }
          }
          return null;
      }
  
      /**
       * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
       * 如向上转型到Object仍无法找到, 返回null.
       * 匹配函数名+参数类型。
       * <p>
       * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
       *
       * @param obj            类名称
       * @param methodName     方法名称
       * @param parameterTypes 参数类型
       * @return
       */
      public static Method getAccessibleMethod(final Object obj, final String methodName,
                                               final Class<?>... parameterTypes) {
  
          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) {
                  // Method不在当前类定义,继续向上转型
                  continue;// new add
              }
          }
          return null;
      }
  
      /**
       * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
       * 如向上转型到Object仍无法找到, 返回null.
       * 只匹配函数名。
       * <p>
       * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
       *
       * @param obj        类名称
       * @param methodName 方法名称
       * @return
       */
      public static Method getAccessibleMethod(final Object obj, final String methodName) {
          for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
              Method[] methods = searchType.getDeclaredMethods();
              for (Method method : methods) {
                  if (method.getName().equals(methodName)) {
                      makeAccessible(method);
                      return method;
                  }
              }
          }
          return null;
      }
  
      /**
       * 改变private/protected的方法为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱怨。
       *
       * @param 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 字段
       */
      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 类名
       * @param <T>   泛型
       * @return
       */
      public static <T> Class<T> getClassGenricType(final Class clazz) {
          return getClassGenricType(clazz, 0);
      }
  
      /**
       * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
       * 如无法找到, 返回Object.class.
       *
       * @param clazz 类名
       * @param index 索引
       * @return
       */
      public static Class getClassGenricType(final Class clazz, final int index) {
  
          Type genType = clazz.getGenericSuperclass();
  
          if (!(genType instanceof ParameterizedType)) {
              return Object.class;
          }
  
          Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
  
          if (index >= params.length || index < 0) {
              return Object.class;
          }
          if (!(params[index] instanceof Class)) {
              return Object.class;
          }
  
          return (Class) params[index];
      }
  
  
      /**
       * 将反射时的checked exception转换为unchecked exception.
       *
       * @param e 异常信息
       * @return
       */
      public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
          if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
                  || e instanceof NoSuchMethodException) {
              return new IllegalArgumentException(e);
          } else if (e instanceof InvocationTargetException) {
              return new RuntimeException(((InvocationTargetException) e).getTargetException());
          } else if (e instanceof RuntimeException) {
              return (RuntimeException) e;
          }
          return new RuntimeException("Unexpected Checked Exception.", e);
      }
  
      /**
       * 实例化方法
       *
       * @param object         类名
       * @param methodName     方法名称
       * @param parameterTypes 参数类型
       * @return
       */
      private static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) {
          Method method = null;
          Class clazz = object.getClass();
          while (clazz != Object.class) {
              try {
                  method = clazz.getDeclaredMethod(methodName, parameterTypes);
                  return method;
              } catch (Exception e) {
                  clazz = clazz.getSuperclass();
              }
          }
          return null;
      }
  
      /**
       * 执行方法
       *
       * @param object         类名
       * @param methodName     方法名称
       * @param parameterTypes 参数类型
       * @param parameters     参数值
       * @return
       */
      public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes, Object[] parameters) {
          Method method = getDeclaredMethod(object, methodName, parameterTypes);
  
          if (method == null) {
              System.err.println(object.getClass() + "未获取到" + methodName + "方法!");
              return null;
          }
  
          method.setAccessible(true);
          try {
              if (method != null) {
                  return method.invoke(object, parameters);
              }
          } catch (IllegalArgumentException e) {
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              e.printStackTrace();
          } catch (InvocationTargetException e) {
              e.printStackTrace();
          }
  
          return null;
      }
  
  
      /**
       * 调用Getter方法.
       * 支持多级，如：对象名.对象名.方法
       *
       * @param obj          类名称
       * @param propertyName 属性名称
       * @return
       */
      public static Object invokeGetter(Object obj, String propertyName) {
          Object object = obj;
          for (String name : propertyName.split(".")) {
              String getterMethodName = GETTER_PREFIX + name;
              object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
          }
          return object;
      }
  
      /**
       * 调用Setter方法, 仅匹配方法名。
       * 支持多级，如：对象名.对象名.方法
       *
       * @param obj          类名称
       * @param propertyName 属性名称
       * @param value        属性值
       */
      public static void invokeSetter(Object obj, String propertyName, Object value) {
          Object object = obj;
          String[] names = propertyName.split(".");
          for (int i = 0; i < names.length; i++) {
              if (i < names.length - 1) {
                  String getterMethodName = GETTER_PREFIX + names[i];
                  object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
              } else {
                  String setterMethodName = SETTER_PREFIX + names[i];
                  invokeMethod(object, setterMethodName, new Object[]{value});
              }
          }
      }
  
      /**
       * 对类的常量设置值
       *
       * @param object    类名
       * @param fieldName 字段名称
       * @param value     值
       */
      public static void setFieldValue(Object object, String fieldName, Object value) {
          Field field = getAccessibleField(object, fieldName);
          if (field == null) {
              throw new IllegalArgumentException(object.getClass() + "未获取到" + fieldName + "属性!");
          }
          try {
              field.set(object, value);
          } catch (IllegalArgumentException e) {
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              e.printStackTrace();
          }
      }
  
      /**
       * 获取类常量的值
       *
       * @param object    类名
       * @param fieldName 字段名称
       * @return
       */
      public static Object getFieldValue(Object object, String fieldName) {
          Field field = getAccessibleField(object, fieldName);
  
          if (field == null) {
              throw new IllegalArgumentException(object.getClass() + "未获取到" + fieldName + "属性!");
          }
          try {
              return field.get(object);
          } catch (Exception e) {
              e.printStackTrace();
          }
          return null;
      }
  
  }
  