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

xdean.jex.util.reflect.ReflectUtil Maven / Gradle / Ivy

The newest version!
package xdean.jex.util.reflect;

import static xdean.jex.util.lang.ExceptionUtil.uncheck;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;

public class ReflectUtil {

  private static final UnaryOperator EXECUTABLE_GET_ROOT;
  private static final Function, Method[]> CLASS_GET_ROOT_METHODS;
  private static final UnaryOperator FIELD_GET_ROOT;
  private static final Function, Field[]> CLASS_GET_ROOT_FIELDS;
  static {
    try {
      Method getRootMethod = Executable.class.getDeclaredMethod("getRoot");
      getRootMethod.setAccessible(true);
      EXECUTABLE_GET_ROOT = m -> uncheck(() -> (Executable) getRootMethod.invoke(m));
      Method getRootMethods = Class.class.getDeclaredMethod("privateGetPublicMethods");
      getRootMethods.setAccessible(true);
      CLASS_GET_ROOT_METHODS = c -> uncheck(() -> (Method[]) getRootMethods.invoke(c));

      Field getRootField = Field.class.getDeclaredField("root");
      getRootField.setAccessible(true);
      FIELD_GET_ROOT = f -> uncheck(() -> (Field) getRootField.get(f));
      Method getRootFields = Class.class.getDeclaredMethod("privateGetPublicFields", Set.class);
      getRootFields.setAccessible(true);
      CLASS_GET_ROOT_FIELDS = c -> uncheck(() -> (Field[]) getRootFields.invoke(c, new Object[] { null }));
    } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) {
      throw new IllegalStateException("ReflectUtil init fail, check your java version.", e);
    }
  }

  public static void setModifiers(AccessibleObject ao, int modifier) {
    Arrays.stream(getAllFields(ao.getClass()))
        .filter(f -> f.getName().equals("modifiers"))
        .peek(f -> f.setAccessible(true))
        .forEach(f -> uncheck(() -> f.set(ao, modifier)));
  }

  /**
   * Get root of the method.
   */
  public static Method getRootMethod(Method m) {
    return getRootExecutable(m);
  }

  /**
   * Get root of the executable.
   */
  @SuppressWarnings("unchecked")
  public static  T getRootExecutable(T m) {
    return (T) EXECUTABLE_GET_ROOT.apply(m);
  }

  /**
   * Get root public methods of the class.
   */
  public static Method[] getRootMethods(Class clz) {
    return CLASS_GET_ROOT_METHODS.apply(clz);
  }

  /**
   * Get root of the field.
   */
  public static Field getRootField(Field f) {
    return FIELD_GET_ROOT.apply(f);
  }

  /**
   * Get root public fields of the class.
   */
  public static Field[] getRootFields(Class clz) {
    return CLASS_GET_ROOT_FIELDS.apply(clz);
  }

  /**
   * Get field value by name
   *
   * @param clz
   * @param t
   * @param fieldName
   * @return
   * @throws NoSuchFieldException
   */
  @SuppressWarnings("unchecked")
  public static  O getFieldValue(Class clz, T t, String fieldName) throws NoSuchFieldException {
    Field field = clz.getDeclaredField(fieldName);
    field.setAccessible(true);
    try {
      return (O) field.get(t);
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(e);
    }
  }

  /**
   * Get all fields
   *
   * @param clz
   * @param includeStatic include static fields or not
   * @return
   */
  public static Field[] getAllFields(Class clz, boolean includeStatic) {
    return Arrays.stream(getAllFields(clz))
        .filter(f -> includeStatic || !Modifier.isStatic(f.getModifiers()))
        .toArray(Field[]::new);
  }

  /**
   * Get all fields
   *
   * @param clz
   * @return
   */
  public static Field[] getAllFields(Class clz) {
    List list = new ArrayList<>();
    do {
      list.addAll(Arrays.asList(clz.getDeclaredFields()));
    } while ((clz = clz.getSuperclass()) != null);
    return list.toArray(new Field[list.size()]);
  }

  /**
   * Get all methods
   *
   * @param clz
   * @return
   */
  public static Method[] getAllMethods(Class clz) {
    Set set = new HashSet<>();
    List> classes = new ArrayList<>();
    classes.add(clz);
    classes.addAll(Arrays.asList(getAllSuperClasses(clz)));
    classes.addAll(Arrays.asList(getAllInterfaces(clz)));
    for (Class c : classes) {
      set.addAll(Arrays.asList(c.getDeclaredMethods()));
    }
    return set.toArray(new Method[set.size()]);
  }

  /**
   * Get all super classes
   *
   * @param clz
   * @return
   */
  public static Class[] getAllSuperClasses(Class clz) {
    List> list = new ArrayList<>();
    while ((clz = clz.getSuperclass()) != null) {
      list.add(clz);
    }
    return list.toArray(new Class[list.size()]);
  }

  /**
   * Get all interfaces
   *
   * @param clz
   * @return
   */
  public static Class[] getAllInterfaces(Class clz) {
    HashSet> set = new HashSet<>();
    getAllInterfaces(clz, set);
    return set.toArray(new Class[set.size()]);
  }

  private static void getAllInterfaces(Class clz, Set> visited) {
    if (clz.getSuperclass() != null) {
      getAllInterfaces(clz.getSuperclass(), visited);
    }
    for (Class c : clz.getInterfaces()) {
      if (visited.add(c)) {
        getAllInterfaces(c, visited);
      }
    }
  }

  /**
   * Get the name of the class who calls the caller.
* For example. The following code will print "A". * *
   * class A {
   *   static void fun() {
   *     B.fun();
   *   }
   * }
   *
   * class B {
   *   static void fun() {
   *     System.out.println(ReflectUtil.getCallerClassName());
   *   }
   * }
   * 
* * @return */ public static String getCallerClassName() { return getCaller().getClassName(); } public static StackTraceElement getCaller() { return getCaller(1, true); } /** * Get caller stack info. * * @param deep Deep to search the caller class.If deep is 0, it returns the class who calls this method. * @param ignoreSameClass If it is true, calling in same class will be ignored. * @return */ public static StackTraceElement getCaller(int deep, boolean ignoreSameClass) { // index 0 is Thread.getStackTrace // index 1 is ReflectUtil.getCallerClassName StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); StackTraceElement currentStack = stElements[1]; int found = deep + 1; for (int i = 1; i < stElements.length; i++) { StackTraceElement nextStack = stElements[i]; if (nextStack.getClassName().equals(ReflectUtil.class.getName())) { continue; } if (!ignoreSameClass || !currentStack.getClassName().equals(nextStack.getClassName())) { currentStack = nextStack; found--; } if (found == 0) { return currentStack; } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy