类操作工具

类名:ClassUtil

getMethodParameter

/**
 * 获取方法参数信息
 *
 * @param constructor    构造器
 * @param parameterIndex 参数序号
 * @return {MethodParameter}
 */
ClassUtil.getMethodParameter(Constructor<?> constructor, int parameterIndex);

getMethodParameter

/**
 * 获取方法参数信息
 *
 * @param method         方法
 * @param parameterIndex 参数序号
 * @return {MethodParameter}
 */
ClassUtil.getMethodParameter(Method method, int parameterIndex);

getAnnotation

/**
 * 获取Annotation
 *
 * @param method         Method
 * @param annotationType 注解类
 * @param <A>            泛型标记
 * @return {Annotation}
 */
ClassUtil.getAnnotation(Method method, Class<A> annotationType);

getAnnotation

/**
 * 获取Annotation
 *
 * @param handlerMethod  HandlerMethod
 * @param annotationType 注解类
 * @param <A>            泛型标记
 * @return {Annotation}
 */
ClassUtil.getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType);

isAnnotated

/**
 * 判断是否有注解 Annotation
 *
 * @param method         Method
 * @param annotationType 注解类
 * @param <A>            泛型标记
 * @return {boolean}
 */
ClassUtil.isAnnotated(Method method, Class<A> annotationType);

getDefaultClassLoader

/**
 * Return the default ClassLoader to use: typically the thread context
 * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
 * class will be used as fallback.
 * <p>Call this method if you intend to use the thread context ClassLoader
 * in a scenario where you clearly prefer a non-null ClassLoader reference:
 * for example, for class path resource loading (but not necessarily for
 * {@code Class.forName}, which accepts a {@code null} ClassLoader
 * reference as well).
 * @return the default ClassLoader (only {@code null} if even the system
 * ClassLoader isn't accessible)
 * @see Thread#getContextClassLoader()
 * @see ClassLoader#getSystemClassLoader()
 */
ClassUtil.getDefaultClassLoader();

overrideThreadContextClassLoader

/**
 * Override the thread context ClassLoader with the environment's bean ClassLoader
 * if necessary, i.e. if the bean ClassLoader is not equivalent to the thread
 * context ClassLoader already.
 * @param classLoaderToUse the actual ClassLoader to use for the thread context
 * @return the original thread context ClassLoader, or {@code null} if not overridden
 */
ClassUtil.overrideThreadContextClassLoader(ClassLoader classLoaderToUse);

forName

/**
 * Replacement for {@code Class.forName()} that also returns Class instances
 * for primitives (e.g. "int") and array class names (e.g. "String[]").
 * Furthermore, it is also capable of resolving inner class names in Java source
 * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
 * @param name the name of the Class
 * @param classLoader the class loader to use
 * (may be {@code null}, which indicates the default class loader)
 * @return a class instance for the supplied name
 * @throws ClassNotFoundException if the class was not found
 * @throws LinkageError if the class file could not be loaded
 * @see Class#forName(String, boolean, ClassLoader)
 */
ClassUtil.forName(String name, ClassLoader classLoader);

resolveClassName

/**
 * Resolve the given class name into a Class instance. Supports
 * primitives (like "int") and array class names (like "String[]").
 * <p>This is effectively equivalent to the {@code forName}
 * method with the same arguments, with the only difference being
 * the exceptions thrown in case of class loading failure.
 * @param className the name of the Class
 * @param classLoader the class loader to use
 * (may be {@code null}, which indicates the default class loader)
 * @return a class instance for the supplied name
 * @throws IllegalArgumentException if the class name was not resolvable
 * (that is, the class could not be found or the class file could not be loaded)
 * @throws IllegalStateException if the corresponding class is resolvable but
 * there was a readability mismatch in the inheritance hierarchy of the class
 * (typically a missing dependency declaration in a Jigsaw module definition
 * for a superclass or interface implemented by the class to be loaded here)
 * @see #forName(String, ClassLoader)
 */
ClassUtil.resolveClassName(String className, ClassLoader classLoader);

isPresent

/**
 * Determine whether the {@link Class} identified by the supplied name is present
 * and can be loaded. Will return {@code false} if either the class or
 * one of its dependencies is not present or cannot be loaded.
 * @param className the name of the class to check
 * @param classLoader the class loader to use
 * (may be {@code null} which indicates the default class loader)
 * @return whether the specified class is present (including all of its
 * superclasses and interfaces)
 * @throws IllegalStateException if the corresponding class is resolvable but
 * there was a readability mismatch in the inheritance hierarchy of the class
 * (typically a missing dependency declaration in a Jigsaw module definition
 * for a superclass or interface implemented by the class to be checked here)
 */
ClassUtil.isPresent(String className, ClassLoader classLoader);

isVisible

/**
 * Check whether the given class is visible in the given ClassLoader.
 * @param clazz the class to check (typically an interface)
 * @param classLoader the ClassLoader to check against
 * (may be {@code null} in which case this method will always return {@code true})
 */
ClassUtil.isVisible(Class<?> clazz, ClassLoader classLoader);

isCacheSafe

/**
 * Check whether the given class is cache-safe in the given context,
 * i.e. whether it is loaded by the given ClassLoader or a parent of it.
 * @param clazz the class to analyze
 * @param classLoader the ClassLoader to potentially cache metadata in
 * (may be {@code null} which indicates the system class loader)
 */
ClassUtil.isCacheSafe(Class<?> clazz, ClassLoader classLoader);

resolvePrimitiveClassName

/**
 * Resolve the given class name as primitive class, if appropriate,
 * according to the JVM's naming rules for primitive classes.
 * <p>Also supports the JVM's internal class names for primitive arrays.
 * Does <i>not</i> support the "[]" suffix notation for primitive arrays;
 * this is only supported by {@link #forName(String, ClassLoader)}.
 * @param name the name of the potentially primitive class
 * @return the primitive class, or {@code null} if the name does not denote
 * a primitive class or primitive array class
 */
ClassUtil.resolvePrimitiveClassName(String name);

isPrimitiveWrapper

/**
 * Check if the given class represents a primitive wrapper,
 * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, Double, or
 * Void.
 * @param clazz the class to check
 * @return whether the given class is a primitive wrapper class
 */
ClassUtil.isPrimitiveWrapper(Class<?> clazz);

isPrimitiveOrWrapper

/**
 * Check if the given class represents a primitive (i.e. boolean, byte,
 * char, short, int, long, float, or double), {@code void}, or a wrapper for
 * those types (i.e. Boolean, Byte, Character, Short, Integer, Long, Float,
 * Double, or Void).
 * @param clazz the class to check
 * @return {@code true} if the given class represents a primitive, void, or
 * a wrapper class
 */
ClassUtil.isPrimitiveOrWrapper(Class<?> clazz);

isPrimitiveArray

/**
 * Check if the given class represents an array of primitives,
 * i.e. boolean, byte, char, short, int, long, float, or double.
 * @param clazz the class to check
 * @return whether the given class is a primitive array class
 */
ClassUtil.isPrimitiveArray(Class<?> clazz);

isPrimitiveWrapperArray

/**
 * Check if the given class represents an array of primitive wrappers,
 * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
 * @param clazz the class to check
 * @return whether the given class is a primitive wrapper array class
 */
ClassUtil.isPrimitiveWrapperArray(Class<?> clazz);

resolvePrimitiveIfNecessary

/**
 * Resolve the given class if it is a primitive class,
 * returning the corresponding primitive wrapper type instead.
 * @param clazz the class to check
 * @return the original class, or a primitive wrapper for the original primitive type
 */
ClassUtil.resolvePrimitiveIfNecessary(Class<?> clazz);

isAssignable

/**
 * Check if the right-hand side type may be assigned to the left-hand side
 * type, assuming setting by reflection. Considers primitive wrapper
 * classes as assignable to the corresponding primitive types.
 * @param lhsType the target type
 * @param rhsType the value type that should be assigned to the target type
 * @return if the target type is assignable from the value type
 * @see TypeUtils#isAssignable(java.lang.reflect.Type, java.lang.reflect.Type)
 */
ClassUtil.isAssignable(Class<?> lhsType, Class<?> rhsType);

isAssignableValue

/**
 * Determine if the given type is assignable from the given value,
 * assuming setting by reflection. Considers primitive wrapper classes
 * as assignable to the corresponding primitive types.
 * @param type the target type
 * @param value the value that should be assigned to the type
 * @return if the type is assignable from the value
 */
ClassUtil.isAssignableValue(Class<?> type, Object value);

convertResourcePathToClassName

/**
 * Convert a "/"-based resource path to a "."-based fully qualified class name.
 * @param resourcePath the resource path pointing to a class
 * @return the corresponding fully qualified class name
 */
ClassUtil.convertResourcePathToClassName(String resourcePath);

convertClassNameToResourcePath

/**
 * Convert a "."-based fully qualified class name to a "/"-based resource path.
 * @param className the fully qualified class name
 * @return the corresponding resource path, pointing to the class
 */
ClassUtil.convertClassNameToResourcePath(String className);

addResourcePathToPackagePath

/**
 * Return a path suitable for use with {@code ClassLoader.getResource}
 * (also suitable for use with {@code Class.getResource} by prepending a
 * slash ('/') to the return value). Built by taking the package of the specified
 * class file, converting all dots ('.') to slashes ('/'), adding a trailing slash
 * if necessary, and concatenating the specified resource name to this.
 * <br/>As such, this function may be used to build a path suitable for
 * loading a resource file that is in the same package as a class file,
 * although {@link org.springframework.core.io.ClassPathResource} is usually
 * even more convenient.
 * @param clazz the Class whose package will be used as the base
 * @param resourceName the resource name to append. A leading slash is optional.
 * @return the built-up resource path
 * @see ClassLoader#getResource
 * @see Class#getResource
 */
ClassUtil.addResourcePathToPackagePath(Class<?> clazz, String resourceName);

classPackageAsResourcePath

/**
 * Given an input class object, return a string which consists of the
 * class's package name as a pathname, i.e., all dots ('.') are replaced by
 * slashes ('/'). Neither a leading nor trailing slash is added. The result
 * could be concatenated with a slash and the name of a resource and fed
 * directly to {@code ClassLoader.getResource()}. For it to be fed to
 * {@code Class.getResource} instead, a leading slash would also have
 * to be prepended to the returned value.
 * @param clazz the input class. A {@code null} value or the default
 * (empty) package will result in an empty string ("") being returned.
 * @return a path which represents the package name
 * @see ClassLoader#getResource
 * @see Class#getResource
 */
ClassUtil.classPackageAsResourcePath(Class<?> clazz);

classNamesToString

/**
 * Build a String that consists of the names of the classes/interfaces
 * in the given array.
 * <p>Basically like {@code AbstractCollection.toString()}, but stripping
 * the "class "/"interface " prefix before every class name.
 * @param classes an array of Class objects
 * @return a String of form "[com.foo.Bar, com.foo.Baz]"
 * @see java.util.AbstractCollection#toString()
 */
ClassUtil.classNamesToString(Class<?> classes);

classNamesToString

/**
 * Build a String that consists of the names of the classes/interfaces
 * in the given collection.
 * <p>Basically like {@code AbstractCollection.toString()}, but stripping
 * the "class "/"interface " prefix before every class name.
 * @param classes a Collection of Class objects (may be {@code null})
 * @return a String of form "[com.foo.Bar, com.foo.Baz]"
 * @see java.util.AbstractCollection#toString()
 */
ClassUtil.classNamesToString(Collection<Class<?>> classes);

toClassArray

/**
 * Copy the given {@code Collection} into a {@code Class} array.
 * <p>The {@code Collection} must contain {@code Class} elements only.
 * @param collection the {@code Collection} to copy
 * @return the {@code Class} array
 * @since 3.1
 * @see StringUtils#toStringArray
 */
ClassUtil.toClassArray(Collection<Class<?>> collection);

getAllInterfaces

/**
 * Return all interfaces that the given instance implements as an array,
 * including ones implemented by superclasses.
 * @param instance the instance to analyze for interfaces
 * @return all interfaces that the given instance implements as an array
 */
ClassUtil.getAllInterfaces(Object instance);

getAllInterfacesForClass

/**
 * Return all interfaces that the given class implements as an array,
 * including ones implemented by superclasses.
 * <p>If the class itself is an interface, it gets returned as sole interface.
 * @param clazz the class to analyze for interfaces
 * @return all interfaces that the given object implements as an array
 */
ClassUtil.getAllInterfacesForClass(Class<?> clazz);

getAllInterfacesForClass

/**
 * Return all interfaces that the given class implements as an array,
 * including ones implemented by superclasses.
 * <p>If the class itself is an interface, it gets returned as sole interface.
 * @param clazz the class to analyze for interfaces
 * @param classLoader the ClassLoader that the interfaces need to be visible in
 * (may be {@code null} when accepting all declared interfaces)
 * @return all interfaces that the given object implements as an array
 */
ClassUtil.getAllInterfacesForClass(Class<?> clazz, ClassLoader classLoader);

getAllInterfacesAsSet

/**
 * Return all interfaces that the given instance implements as a Set,
 * including ones implemented by superclasses.
 * @param instance the instance to analyze for interfaces
 * @return all interfaces that the given instance implements as a Set
 */
ClassUtil.getAllInterfacesAsSet(Object instance);

getAllInterfacesForClassAsSet

/**
 * Return all interfaces that the given class implements as a Set,
 * including ones implemented by superclasses.
 * <p>If the class itself is an interface, it gets returned as sole interface.
 * @param clazz the class to analyze for interfaces
 * @return all interfaces that the given object implements as a Set
 */
ClassUtil.getAllInterfacesForClassAsSet(Class<?> clazz);

getAllInterfacesForClassAsSet

/**
 * Return all interfaces that the given class implements as a Set,
 * including ones implemented by superclasses.
 * <p>If the class itself is an interface, it gets returned as sole interface.
 * @param clazz the class to analyze for interfaces
 * @param classLoader the ClassLoader that the interfaces need to be visible in
 * (may be {@code null} when accepting all declared interfaces)
 * @return all interfaces that the given object implements as a Set
 */
ClassUtil.getAllInterfacesForClassAsSet(Class<?> clazz, ClassLoader classLoader);

createCompositeInterface

/**
 * Create a composite interface Class for the given interfaces,
 * implementing the given interfaces in one single Class.
 * <p>This implementation builds a JDK proxy class for the given interfaces.
 * @param interfaces the interfaces to merge
 * @param classLoader the ClassLoader to create the composite Class in
 * @return the merged interface as Class
 * @throws IllegalArgumentException if the specified interfaces expose
 * conflicting method signatures (or a similar constraint is violated)
 * @see java.lang.reflect.Proxy#getProxyClass
 */
ClassUtil.createCompositeInterface(Class<?>[] interfaces, ClassLoader classLoader);

determineCommonAncestor

/**
 * Determine the common ancestor of the given classes, if any.
 * @param clazz1 the class to introspect
 * @param clazz2 the other class to introspect
 * @return the common ancestor (i.e. common superclass, one interface
 * extending the other), or {@code null} if none found. If any of the
 * given classes is {@code null}, the other class will be returned.
 * @since 3.2.6
 */
ClassUtil.determineCommonAncestor(Class<?> clazz1, Class<?> clazz2);

isJavaLanguageInterface

/**
 * Determine whether the given interface is a common Java language interface:
 * {@link Serializable}, {@link Externalizable}, {@link Closeable}, {@link AutoCloseable},
 * {@link Cloneable}, {@link Comparable} - all of which can be ignored when looking
 * for 'primary' user-level interfaces. Common characteristics: no service-level
 * operations, no bean property methods, no default methods.
 * @param ifc the interface to check
 * @since 5.0.3
 */
ClassUtil.isJavaLanguageInterface(Class<?> ifc);

isInnerClass

/**
 * Determine if the supplied class is an <em>inner class</em>,
 * i.e. a non-static member of an enclosing class.
 * @return {@code true} if the supplied class is an inner class
 * @since 5.0.5
 * @see Class#isMemberClass()
 */
ClassUtil.isInnerClass(Class<?> clazz);

isCglibProxy

/**
 * Check whether the given object is a CGLIB proxy.
 * @param object the object to check
 * @see #isCglibProxyClass(Class)
 * @see org.springframework.aop.support.AopUtils#isCglibProxy(Object)
 */
ClassUtil.isCglibProxy(Object object);

isCglibProxyClass

/**
 * Check whether the specified class is a CGLIB-generated class.
 * @param clazz the class to check
 * @see #isCglibProxyClassName(String)
 */
ClassUtil.isCglibProxyClass(Class<?> clazz);

isCglibProxyClassName

/**
 * Check whether the specified class name is a CGLIB-generated class.
 * @param className the class name to check
 */
ClassUtil.isCglibProxyClassName(String className);

getUserClass

/**
 * Return the user-defined class for the given instance: usually simply
 * the class of the given instance, but the original class in case of a
 * CGLIB-generated subclass.
 * @param instance the instance to check
 * @return the user-defined class
 */
ClassUtil.getUserClass(Object instance);

getUserClass

/**
 * Return the user-defined class for the given class: usually simply the given
 * class, but the original class in case of a CGLIB-generated subclass.
 * @param clazz the class to check
 * @return the user-defined class
 */
ClassUtil.getUserClass(Class<?> clazz);

getDescriptiveType

/**
 * Return a descriptive name for the given object's type: usually simply
 * the class name, but component type class name + "[]" for arrays,
 * and an appended list of implemented interfaces for JDK proxies.
 * @param value the value to introspect
 * @return the qualified name of the class
 */
ClassUtil.getDescriptiveType(Object value);

matchesTypeName

/**
 * Check whether the given class matches the user-specified type name.
 * @param clazz the class to check
 * @param typeName the type name to match
 */
ClassUtil.matchesTypeName(Class<?> clazz, String typeName);

getShortName

/**
 * Get the class name without the qualified package name.
 * @param className the className to get the short name for
 * @return the class name of the class without the package name
 * @throws IllegalArgumentException if the className is empty
 */
ClassUtil.getShortName(String className);

getShortName

/**
 * Get the class name without the qualified package name.
 * @param clazz the class to get the short name for
 * @return the class name of the class without the package name
 */
ClassUtil.getShortName(Class<?> clazz);

getShortNameAsProperty

/**
 * Return the short string name of a Java class in uncapitalized JavaBeans
 * property format. Strips the outer class name in case of an inner class.
 * @param clazz the class
 * @return the short name rendered in a standard JavaBeans property format
 * @see java.beans.Introspector#decapitalize(String)
 */
ClassUtil.getShortNameAsProperty(Class<?> clazz);

getClassFileName

/**
 * Determine the name of the class file, relative to the containing
 * package: e.g. "String.class"
 * @param clazz the class
 * @return the file name of the ".class" file
 */
ClassUtil.getClassFileName(Class<?> clazz);

getPackageName

/**
 * Determine the name of the package of the given class,
 * e.g. "java.lang" for the {@code java.lang.String} class.
 * @param clazz the class
 * @return the package name, or the empty String if the class
 * is defined in the default package
 */
ClassUtil.getPackageName(Class<?> clazz);

getPackageName

/**
 * Determine the name of the package of the given fully-qualified class name,
 * e.g. "java.lang" for the {@code java.lang.String} class name.
 * @param fqClassName the fully-qualified class name
 * @return the package name, or the empty String if the class
 * is defined in the default package
 */
ClassUtil.getPackageName(String fqClassName);

getQualifiedName

/**
 * Return the qualified name of the given class: usually simply
 * the class name, but component type class name + "[]" for arrays.
 * @param clazz the class
 * @return the qualified name of the class
 */
ClassUtil.getQualifiedName(Class<?> clazz);

getQualifiedMethodName

/**
 * Return the qualified name of the given method, consisting of
 * fully qualified interface/class name + "." + method name.
 * @param method the method
 * @return the qualified name of the method
 */
ClassUtil.getQualifiedMethodName(Method method);

getQualifiedMethodName

/**
 * Return the qualified name of the given method, consisting of
 * fully qualified interface/class name + "." + method name.
 * @param method the method
 * @param clazz the clazz that the method is being invoked on
 * (may be {@code null} to indicate the method's declaring class)
 * @return the qualified name of the method
 * @since 4.3.4
 */
ClassUtil.getQualifiedMethodName(Method method, Class<?> clazz);

hasConstructor

/**
 * Determine whether the given class has a public constructor with the given signature.
 * <p>Essentially translates {@code NoSuchMethodException} to "false".
 * @param clazz the clazz to analyze
 * @param paramTypes the parameter types of the method
 * @return whether the class has a corresponding constructor
 * @see Class#getConstructor
 */
ClassUtil.hasConstructor(Class<?> clazz, Class<?> paramTypes);

getConstructorIfAvailable

/**
 * Determine whether the given class has a public constructor with the given signature,
 * and return it if available (else return {@code null}).
 * <p>Essentially translates {@code NoSuchMethodException} to {@code null}.
 * @param clazz the clazz to analyze
 * @param paramTypes the parameter types of the method
 * @return the constructor, or {@code null} if not found
 * @see Class#getConstructor
 */
ClassUtil.getConstructorIfAvailable(Class<T> clazz, Class<?> paramTypes);

hasMethod

/**
 * Determine whether the given class has a public method with the given signature.
 * <p>Essentially translates {@code NoSuchMethodException} to "false".
 * @param clazz the clazz to analyze
 * @param methodName the name of the method
 * @param paramTypes the parameter types of the method
 * @return whether the class has a corresponding method
 * @see Class#getMethod
 */
ClassUtil.hasMethod(Class<?> clazz, String methodName, Class<?> paramTypes);

getMethod

/**
 * Determine whether the given class has a public method with the given signature,
 * and return it if available (else throws an {@code IllegalStateException}).
 * <p>In case of any signature specified, only returns the method if there is a
 * unique candidate, i.e. a single public method with the specified name.
 * <p>Essentially translates {@code NoSuchMethodException} to {@code IllegalStateException}.
 * @param clazz the clazz to analyze
 * @param methodName the name of the method
 * @param paramTypes the parameter types of the method
 * (may be {@code null} to indicate any signature)
 * @return the method (never {@code null})
 * @throws IllegalStateException if the method has not been found
 * @see Class#getMethod
 */
ClassUtil.getMethod(Class<?> clazz, String methodName, Class<?> paramTypes);

getMethodIfAvailable

/**
 * Determine whether the given class has a public method with the given signature,
 * and return it if available (else return {@code null}).
 * <p>In case of any signature specified, only returns the method if there is a
 * unique candidate, i.e. a single public method with the specified name.
 * <p>Essentially translates {@code NoSuchMethodException} to {@code null}.
 * @param clazz the clazz to analyze
 * @param methodName the name of the method
 * @param paramTypes the parameter types of the method
 * (may be {@code null} to indicate any signature)
 * @return the method, or {@code null} if not found
 * @see Class#getMethod
 */
ClassUtil.getMethodIfAvailable(Class<?> clazz, String methodName, Class<?> paramTypes);

getMethodCountForName

/**
 * Return the number of methods with a given name (with any argument types),
 * for the given class and/or its superclasses. Includes non-public methods.
 * @param clazz	the clazz to check
 * @param methodName the name of the method
 * @return the number of methods with the given name
 */
ClassUtil.getMethodCountForName(Class<?> clazz, String methodName);

hasAtLeastOneMethodWithName

/**
 * Does the given class or one of its superclasses at least have one or more
 * methods with the supplied name (with any argument types)?
 * Includes non-public methods.
 * @param clazz	the clazz to check
 * @param methodName the name of the method
 * @return whether there is at least one method with the given name
 */
ClassUtil.hasAtLeastOneMethodWithName(Class<?> clazz, String methodName);

getMostSpecificMethod

/**
 * Given a method, which may come from an interface, and a target class used
 * in the current reflective invocation, find the corresponding target method
 * if there is one. E.g. the method may be {@code IFoo.bar()} and the
 * target class may be {@code DefaultFoo}. In this case, the method may be
 * {@code DefaultFoo.bar()}. This enables attributes on that method to be found.
 * <p><b>NOTE:</b> In contrast to {@link org.springframework.aop.support.AopUtils#getMostSpecificMethod},
 * this method does <i>not</i> resolve Java 5 bridge methods automatically.
 * Call {@link org.springframework.core.BridgeMethodResolver#findBridgedMethod}
 * if bridge method resolution is desirable (e.g. for obtaining metadata from
 * the original method definition).
 * <p><b>NOTE:</b> Since Spring 3.1.1, if Java security settings disallow reflective
 * access (e.g. calls to {@code Class#getDeclaredMethods} etc, this implementation
 * will fall back to returning the originally provided method.
 * @param method the method to be invoked, which may come from an interface
 * @param targetClass the target class for the current invocation
 * (may be {@code null} or may not even implement the method)
 * @return the specific target method, or the original method if the
 * {@code targetClass} does not implement it
 * @see #getInterfaceMethodIfPossible
 */
ClassUtil.getMostSpecificMethod(Method method, Class<?> targetClass);

getInterfaceMethodIfPossible

/**
 * Determine a corresponding interface method for the given method handle, if possible.
 * <p>This is particularly useful for arriving at a public exported type on Jigsaw
 * which can be reflectively invoked without an illegal access warning.
 * @param method the method to be invoked, potentially from an implementation class
 * @return the corresponding interface method, or the original method if none found
 * @since 5.1
 * @see #getMostSpecificMethod
 */
ClassUtil.getInterfaceMethodIfPossible(Method method);

isUserLevelMethod

/**
 * Determine whether the given method is declared by the user or at least pointing to
 * a user-declared method.
 * <p>Checks {@link Method#isSynthetic()} (for implementation methods) as well as the
 * {@code GroovyObject} interface (for interface methods; on an implementation class,
 * implementations of the {@code GroovyObject} methods will be marked as synthetic anyway).
 * Note that, despite being synthetic, bridge methods ({@link Method#isBridge()}) are considered
 * as user-level methods since they are eventually pointing to a user-declared generic method.
 * @param method the method to check
 * @return {@code true} if the method can be considered as user-declared; [@code false} otherwise
 */
ClassUtil.isUserLevelMethod(Method method);

getStaticMethod

/**
 * Return a public static method of a class.
 * @param clazz the class which defines the method
 * @param methodName the static method name
 * @param args the parameter types to the method
 * @return the static method, or {@code null} if no static method was found
 * @throws IllegalArgumentException if the method name is blank or the clazz is null
 */
ClassUtil.getStaticMethod(Class<?> clazz, String methodName, Class<?> args);