Package manifold.util

Class ReflectUtil


  • public class ReflectUtil
    extends Object
    A Java reflection utility. Use it to efficiently access classes by name, get/set field values, invoke methods, and use constructors. Notable features include:
    • Intuitive, fluent API
    • Call any method: private, filtered, inaccessible, etc.
    • Get and set the value of a final field
    • Access fields and methods of a class belonging to an inaccessible module
    • Call a super method
    • Call a default interface method esp. for a proxy
    • Call a method structurally with automatic best method matching
    • Fields, methods, and constructors are cached upon use to improve performance
    • Works with all versions of Java beginning with Java 8

    (Use @Jailbreak to avoid writing reflection code. See Type-safe Reflection.)

    • Constructor Detail

      • ReflectUtil

        public ReflectUtil()
    • Method Detail

      • type

        public static Class<?> type​(String fqn)
        Searches the class loader of this class for the specified name, if not found searches the current thread's context class loader.
        Parameters:
        fqn - The qualified name of the type e.g., "java.lang.String" or "java.lang.String[]"
        Returns:
        The Class corresponding with fqn or null if not found
      • type

        public static Class<?> type​(String fqn,
                                    boolean useCallChain)
      • type

        public static Class<?> type​(String fqn,
                                    ClassLoader cl)
        Searches cl for the specified class fqn.
        Parameters:
        fqn - The qualified name of the type e.g., "java.lang.String"
        cl - The class loader to search
        Returns:
        The Class corresponding with fqn or null if not found
      • method

        public static ReflectUtil.LiveMethodRef method​(Object receiver,
                                                       String name,
                                                       Class... params)
        Get a ReflectUtil.LiveMethodRef to the specified method. Typical use:

         method(str, "substring", int.class).invoke(2) 
        Parameters:
        receiver - The object to make the call on
        name - The name of the method to call or a '|' separated list of names, where the first found is used
        params - The types of the method's parameters
        Returns:
        A reference to the specified method, throws RuntimeException if the method is not found. Use ReflectUtil.WithNull to avoid the RuntimeException.
      • method

        public static ReflectUtil.MethodRef method​(String fqn,
                                                   String name,
                                                   Class... params)
        Get a ReflectUtil.MethodRef to the specified method. Typical use:

         method("java.time.LocalTime", "of", int.class, int.class).invokeStatic(5, 30) 
        Parameters:
        fqn - The qualified name of the class containing the method
        name - The name of the method or a '|' separated list of names, where the first found is used
        params - The types of the method's parameters
        Returns:
        A reference to the specified method or null if not found
      • method

        public static ReflectUtil.MethodRef method​(Class<?> cls,
                                                   String name,
                                                   Class... params)
        Get a ReflectUtil.MethodRef to the specified method. Typical use:

         method(LocalTime.class, "of", int.class, int.class).invokeStatic(5, 30) 
        Parameters:
        cls - The class containing the method
        name - The name of the method or a '|' separated list of names, where the first found is used
        params - The types of the method's parameters
        Returns:
        A reference to the specified method or null if not found
      • methodFromName

        public static ReflectUtil.MethodRef methodFromName​(Class<?> cls,
                                                           String name)
        Get a ReflectUtil.MethodRef to the specified name without regard to parameter types. If more than one method has the name, the first one encountered is used, in no particular order. This method should be used only when the named method is not overloaded. Typical use:

         methodByName(LocalTime.class, "isAfter").invoke(source, time) 
        Parameters:
        cls - The class containing the method
        name - The name of the method or a '|' separated list of names, where the first found is used
        Returns:
        A reference to the specified method or null if not found
      • lambdaMethod

        public static ReflectUtil.MethodRef lambdaMethod​(Class<?> lambdaClass)
        Get a ReflectUtil.MethodRef corresponding with the functional interface implemented by lambdaClass.

         lambdaMethod(function.getClass()).invoke(function, args) 
        Returns:
        A reference to the specified method or null if not found
      • invokeDefault

        public static Object invokeDefault​(Object receiver,
                                           Class<?> iface,
                                           String name,
                                           Class<?>[] params,
                                           Object... args)
        This method behaves like the one below it, except this method ensures the iface default method is called even if the receiver overrides it. Essentially, this method is like calling Iface.super.method() from the receiver's perspective.
      • invokeDefault

        public static Object invokeDefault​(Object receiver,
                                           Method method,
                                           Object... args)
        Invoke a default interface method.

        This is useful, for example, for a proxy implementation where there is no explicit implementation of the interface on which to invoke the default method.

        Parameters:
        receiver - The receiver of the call (the proxy instance in the case of a proxy impl).
        method - The default interface method to invoke on receiver.
        args - The arguments to method.
        Returns:
        The return value of method or null if the method has a void return type.
      • field

        public static ReflectUtil.LiveFieldRef field​(Object receiver,
                                                     String name)
        Get a ReflectUtil.LiveFieldRef to the specified field. Typical use:

         String name = field(foo, "name").get(); 
        Parameters:
        receiver - The object having the field
        name - The name of the field or a '|' separated list of names, where the first found is used
        Returns:
        A reference to the specified field, throws RuntimeException if the field is not found. Use ReflectUtil.WithNull to avoid the RuntimeException.
      • field

        public static ReflectUtil.FieldRef field​(String fqn,
                                                 String name)
        Get a ReflectUtil.FieldRef to the specified field. Typical use:

         field("java.time.LocalTime", "hour").get(time); 
        Parameters:
        fqn - The qualified name of the class having the field
        name - The name of the field or a '|' separated list of names, where the first found is used
        Returns:
        A reference to the specified field or null if not found
      • field

        public static ReflectUtil.FieldRef field​(Class<?> cls,
                                                 String name)
        Get a ReflectUtil.FieldRef to the specified field. Typical use:

         field(LocalTime.class, "hour").get(time); 
        Parameters:
        cls - The class having the field
        name - The name of the field or a '|' separated list of names, where the first found is used
        Returns:
        A reference to the specified field or null if not found
      • constructor

        public static ReflectUtil.ConstructorRef constructor​(String fqn,
                                                             Class<?>... params)
        Get a ReflectUtil.ConstructorRef to the specified constructor. Typical use:

         constructor("java.util.ArrayList", int.class).newInstance(32) 
        Parameters:
        fqn - The qualified name of the class to construct
        params - A list of parameter types for the constructor
        Returns:
        A reference to the constructor or null if not found
      • constructor

        public static ReflectUtil.ConstructorRef constructor​(Class<?> cls,
                                                             Class<?>... params)
        Get a ReflectUtil.ConstructorRef to the specified constructor. Typical use:

         constructor(ArrayList.class, int.class).newInstance(32) 
        Parameters:
        cls - The class to construct
        params - A list of parameter types for the constructor
        Returns:
        A reference to the constructor or null if not found
      • setAccessible

        public static void setAccessible​(Field f)
      • setAccessible

        public static void setAccessible​(Method m)
      • setAccessible

        public static void setAccessible​(Constructor c)
      • setAccessible

        public static void setAccessible​(Member m)
      • preloadClassIntoParentLoader

        public static void preloadClassIntoParentLoader​(String fqn,
                                                        URI content,
                                                        ClassLoader wouldBeLoader,
                                                        ClassLoader parentLoader)
        Force class with name fqn to be loaded by parentLoader. Facilitates the case where a class must be declared in a package defined in a parent class loader in order to subclass and use package-local features defined there.

        Note fqn's natural class loader must have the parentLoader in its chain of parent loaders. Also be certain fqn is not already loaded by its natural loader, otherwise LinkageErrors will result.

        Parameters:
        fqn - The qualified name of the class to load
        content - The location of the class resource. With Java 8 this can be wouldBeLoader.getResource(className). But with Java 9 and later the JPMS strictly prohibits a package from existing in two loaders, therefore the class file must be placed in a different package, perhaps prefixed with a suitably named root package, otherwise the VM will throw a LayerInstantiationException when your application loads, before any of your code executes.
        wouldBeLoader - The class loader that would naturally load fqn, must have parentLoader in its parent loader chain
        parentLoader - The class loader to load the class in, must be in the parent chain of wouldBeLoader
      • arePrimitiveTypesAssignable

        public static boolean arePrimitiveTypesAssignable​(Class toType,
                                                          Class fromType)
      • findBestMethod

        public static Method findBestMethod​(Method structMethod,
                                            Class receiverClass)
      • setContextClassLoader

        public static void setContextClassLoader​(ClassLoader cl)
        Uses reflection to set Thread#contextClassLoader primarily to sidestep a bug introduced in the JDK where if a SecurityManager is set, ForkJoinPool uses InnocuousForkJoinWorkerThread which overrides setContextClassLoader() to prevent it from being used by throwing an exception. It is best to use reflection to set the contextClassLoader directly.

        Note, the JDK issue happens when launching the IntelliJ runIde task for plugin dev.