Class MethodInfo

All Implemented Interfaces:
Comparable<MethodInfo>, Annotatable

public class MethodInfo extends ExecutableInfo implements Comparable<MethodInfo>, Annotatable
Lightweight utility class for introspecting information about a Java method.

This class provides a convenient wrapper around Method that extends the standard Java reflection API with additional functionality for method introspection, annotation handling, and hierarchy traversal. It's designed to be lightweight, thread-safe, and cached for efficient reuse.

Features:
  • Method introspection - access method metadata, parameters, return type, exceptions
  • Annotation support - get annotations from method and overridden methods in hierarchy
  • Hierarchy traversal - find matching methods in parent classes and interfaces
  • Type-safe access - wrapper around reflection with convenient methods
  • Thread-safe - instances are immutable and safe for concurrent access
Use Cases:
  • Introspecting method metadata for code generation or analysis
  • Finding annotations on methods including those from parent classes
  • Discovering method hierarchies and overridden methods
  • Working with method parameters and return types
  • Building frameworks that need to analyze method signatures
Usage:

// Get MethodInfo from a class ClassInfo ci = ClassInfo.of(MyClass.class); MethodInfo method = ci.getMethod("myMethod"); // Get return type ClassInfo returnType = method.getReturnType(); // Get annotations including from parent methods List<AnnotationInfo<MyAnnotation>> annotations = method.getAnnotations(MyAnnotation.class).toList(); // Find matching methods in hierarchy List<MethodInfo> matching = method.getMatchingMethods();

See Also:
  • Constructor Details

    • MethodInfo

      protected MethodInfo(ClassInfo declaringClass, Method inner)
      Constructor.

      Creates a new MethodInfo wrapper for the specified method. This constructor is protected and should not be called directly. Use the static factory methods of(Method) or obtain MethodInfo instances from ClassInfo.getMethod(Method).

      Parameters:
      declaringClass - The ClassInfo for the class that declares this method.
      inner - The method being wrapped.
  • Method Details

    • of

      public static MethodInfo of(Class<?> declaringClass, Method inner)
      Creates a MethodInfo wrapper for the specified method.
      Example:

      Method m = MyClass.class.getMethod("myMethod"); MethodInfo mi = MethodInfo.of(MyClass.class, m);

      Parameters:
      declaringClass - The class that declares this method. Must not be null.
      inner - The method being wrapped. Must not be null.
      Returns:
      A new MethodInfo object wrapping the method.
    • of

      public static MethodInfo of(ClassInfo declaringClass, Method inner)
      Creates a MethodInfo wrapper for the specified method.
      Example:

      ClassInfo ci = ClassInfo.of(MyClass.class); Method m = MyClass.class.getMethod("myMethod"); MethodInfo mi = MethodInfo.of(ci, m);

      Parameters:
      declaringClass - The ClassInfo for the class that declares this method. Must not be null.
      inner - The method being wrapped. Must not be null.
      Returns:
      A new MethodInfo object wrapping the method.
    • of

      public static MethodInfo of(Method inner)
      Creates a MethodInfo wrapper for the specified method.

      This convenience method automatically determines the declaring class from the method.

      Example:

      Method m = MyClass.class.getMethod("myMethod"); MethodInfo mi = MethodInfo.of(m);

      Parameters:
      inner - The method being wrapped. Must not be null.
      Returns:
      A new MethodInfo object wrapping the method.
    • accessible

      Description copied from class: ExecutableInfo
      Attempts to call x.setAccessible(true) and quietly ignores security exceptions.
      Overrides:
      accessible in class ExecutableInfo
      Returns:
      This object.
    • compareTo

      public int compareTo(MethodInfo o)
      Specified by:
      compareTo in interface Comparable<MethodInfo>
    • getAnnotatableType

      Description copied from interface: Annotatable
      Returns the type of this annotatable object.
      Specified by:
      getAnnotatableType in interface Annotatable
      Returns:
      The type of annotatable object this represents.
    • getAnnotatedReturnType

      Returns an AnnotatedType object that represents the use of a type to specify the return type of the method.

      Same as calling Method.getAnnotatedReturnType().

      Example:

      // For method: public @NotNull String getName() MethodInfo mi = ClassInfo.of(MyClass.class).getMethod("getName"); AnnotatedType aType = mi.getAnnotatedReturnType(); // Check for @NotNull on the return type

      Returns:
      An AnnotatedType object representing the return type.
      See Also:
    • getAnnotations

      Returns all annotations on this method and parent overridden methods in child-to-parent order.

      Results include annotations from:

      • This method
      • Matching methods in parent classes
      • Matching methods in interfaces

      Note on Repeatable Annotations: Repeatable annotations (those marked with @Repeatable) are automatically expanded into their individual annotation instances. For example, if a method has multiple @Bean annotations, this method returns each @Bean annotation separately, rather than the container annotation.

      List is unmodifiable.

      Returns:
      A list of all annotations on this method and overridden methods.
      Repeatable annotations are expanded into individual instances.
    • getAnnotations

      public <A extends Annotation> Stream<AnnotationInfo<A>> getAnnotations(Class<A> type)
      Returns all annotations of the specified type on this method and parent overridden methods in child-to-parent order.

      Results include annotations from:

      • This method
      • Matching methods in parent classes
      • Matching methods in interfaces

      Note on Repeatable Annotations: If the specified annotation type is repeatable (marked with @Repeatable), this method automatically expands container annotations into individual instances. This allows you to filter for a repeatable annotation and get back all individual occurrences without manually handling the container.

      Example:

      // Get all @Bean annotations on this method and overridden methods Stream<AnnotationInfo<Bean>> beans = methodInfo.getAnnotations(Bean.class); // If method has @Beans(), both individual @Bean instances are returned

      Type Parameters:
      A - The annotation type.
      Parameters:
      type - The annotation type to filter by.
      Returns:
      A stream of matching annotation infos in child-to-parent order.
      Repeatable annotations are expanded into individual instances.
    • getDefaultValue

      Returns the default value for the annotation member represented by this method.

      Same as calling Method.getDefaultValue().

      Returns null if this method is not an annotation member, or if the annotation member has no default value.

      Example:

      // For annotation: @interface MyAnnotation { String value() default "default"; } MethodInfo mi = ClassInfo.of(MyAnnotation.class).getMethod("value"); Object defaultValue = mi.getDefaultValue(); // defaultValue is "default"

      Returns:
      The default value, or null if none.
      See Also:
    • getGenericReturnType

      Returns a Type object that represents the formal return type of the method.

      Same as calling Method.getGenericReturnType().

      If the return type is a parameterized type, the Type object returned reflects the actual type parameters used in the source code.

      Example:

      // For method: public List<String> getValues() MethodInfo mi = ClassInfo.of(MyClass.class).getMethod("getValues"); Type returnType = mi.getGenericReturnType(); if (returnType instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType)returnType; // pType.getActualTypeArguments()[0] is String.class }

      Returns:
      A Type object representing the formal return type.
      See Also:
    • getLabel

      public String getLabel()
      Description copied from interface: Annotatable
      Returns a human-readable label for this annotatable element.

      The label format depends on the type of annotatable:

      • CLASS_TYPE - Simple class name (e.g., "MyClass")
      • METHOD_TYPE - Class and method with parameter types (e.g., "MyClass.myMethod(String,int)")
      • FIELD_TYPE - Class and field name (e.g., "MyClass.myField")
      • CONSTRUCTOR_TYPE - Class and constructor with parameter types (e.g., "MyClass.MyClass(String)")
      • PARAMETER_TYPE - Class, method/constructor, and parameter index (e.g., "MyClass.myMethod[0]")
      • PACKAGE_TYPE - Package name (e.g., "com.example.package")
      Specified by:
      getLabel in interface Annotatable
      Returns:
      The human-readable label for this annotatable element.
    • getMatchingMethods

      Returns this method and all matching methods up the hierarchy chain.

      Searches parent classes and interfaces for methods with matching name and parameter types. Results are returned in the following order:

      1. This method
      2. Any matching methods on declared interfaces of this class
      3. Matching method on the parent class
      4. Any matching methods on the declared interfaces of the parent class
      5. Continue up the hierarchy
      Examples:

      // Interface and class hierarchy: interface I1 { void foo(String s); } class A { void foo(String s) {} } interface I2 { void foo(String s); } class B extends A implements I2 { @Override void foo(String s) {} } // For B.foo(), returns: [B.foo, I2.foo, A.foo, I1.foo] MethodInfo mi = ...; List<MethodInfo> matching = mi.getMatchingMethods();

      Returns:
      A list of matching methods including this one, in child-to-parent order.
    • getName

      public String getName()
      Returns the name of this method.
      Returns:
      The name of this method
    • getPropertyName

      Returns the bean property name if this is a getter or setter.
      Returns:
      The bean property name, or null if this isn't a getter or setter.
    • getReturnType

      Returns the generic return type of this method as a ClassInfo object.
      Returns:
      The generic return type of this method.
    • getSignature

      public String getSignature()
      Returns the signature of this method.

      For no-arg methods, the signature will be a simple string such as "toString". For methods with one or more args, the arguments will be fully-qualified class names (e.g. "append(java.util.StringBuilder,boolean)")

      Returns:
      The methods signature.
    • hasAllParameters

      public boolean hasAllParameters(Class<?>... requiredParams)
      Returns true if this method has at least the specified parameters.

      Method may or may not have additional parameters besides those specified.

      Parameters:
      requiredParams - The parameter types to check for.
      Returns:
      true if this method has at least the specified parameters.
    • hasAnnotation

      public <A extends Annotation> boolean hasAnnotation(Class<A> type)
      Returns true if the specified annotation is present on this method or any matching methods in parent classes/interfaces.

      This method searches through all matching methods in the hierarchy.

      Overrides:
      hasAnnotation in class ExecutableInfo
      Type Parameters:
      A - The annotation type to look for.
      Parameters:
      type - The annotation to look for.
      Returns:
      true if the specified annotation is present on this method.
    • hasOnlyParameterTypes

      public boolean hasOnlyParameterTypes(Class<?>... args)
      Returns true if the parameters on the method only consist of the types specified in the list.

      Note: This method is not meant to be used on methods with duplicate parameter types. It checks if each parameter type is present in the specified list, but does not verify that the count of each type matches exactly.

      Example:

      // Example method: public void foo(String bar, Integer baz); fooMethod.hasOnlyParameterTypes(String.class, Integer.class); // True. fooMethod.hasOnlyParameterTypes(String.class, Integer.class, Map.class); // True. fooMethod.hasOnlyParameterTypes(String.class); // False.

      Parameters:
      args - The valid class types (exact) for the arguments.
      Returns:
      true if the method parameters only consist of the types specified in the list.
    • hasParameter

      public boolean hasParameter(Class<?> requiredParam)
      Returns true if this method has the specified parameter.

      Method may or may not have additional parameters besides the one specified.

      Parameters:
      requiredParam - The parameter type to check for.
      Returns:
      true if this method has at least the specified parameter.
    • hasReturnType

      public boolean hasReturnType(Class<?> c)
      Returns true if this method has this return type.
      Parameters:
      c - The return type to test for.
      Returns:
      true if this method has this return type.
    • hasReturnType

      public boolean hasReturnType(ClassInfo ci)
      Returns true if this method has this return type.
      Parameters:
      ci - The return type to test for.
      Returns:
      true if this method has this return type.
    • hasReturnTypeParent

      public boolean hasReturnTypeParent(Class<?> c)
      Returns true if this method has this parent return type.
      Parameters:
      c - The return type to test for.
      Returns:
      true if this method has this parent return type.
    • hasReturnTypeParent

      public boolean hasReturnTypeParent(ClassInfo ci)
      Returns true if this method has this parent return type.
      Parameters:
      ci - The return type to test for.
      Returns:
      true if this method has this parent return type.
    • inner

      public Method inner()
      Returns the wrapped method.
      Returns:
      The wrapped method.
    • equals

      public boolean equals(Object obj)
      Compares this MethodInfo with the specified object for equality.

      Two MethodInfo objects are considered equal if they wrap the same underlying Method object. This delegates to the underlying Method.equals(Object) method.

      This method makes MethodInfo suitable for use as keys in hash-based collections such as HashMap and HashSet.

      Overrides:
      equals in class Object
      Parameters:
      obj - The object to compare with.
      Returns:
      true if the objects are equal, false otherwise.
    • hashCode

      public int hashCode()
      Returns a hash code value for this MethodInfo.

      This combines the hash code of the underlying Method with the hash code of the declaring class to ensure that methods from different subclasses that inherit the same method are not considered equal.

      This method makes MethodInfo suitable for use as keys in hash-based collections such as HashMap and HashSet.

      Overrides:
      hashCode in class Object
      Returns:
      A hash code value for this MethodInfo.
    • invoke

      public <T> T invoke(Object obj, Object... args) throws ExecutableException
      Shortcut for calling the invoke method on the underlying method.
      Type Parameters:
      T - The method return type.
      Parameters:
      obj - the object the underlying method is invoked from.
      args - the arguments used for the method call
      Returns:
      The object returned from the method.
      Throws:
      ExecutableException - Exception occurred on invoked constructor/method/field.
    • invokeLenient

      public Object invokeLenient(Object pojo, Object... args) throws ExecutableException
      Invokes the specified method using lenient argument matching.

      Lenient matching allows arguments to be matched to parameters based on parameter types.
      Arguments can be in any order.
      Extra arguments will be ignored.
      Missing arguments will be left null.

      Note that this only works for methods that have distinguishable argument types.
      It's not going to work on methods with generic argument types like Object

      Parameters:
      pojo - The POJO the method is being called on.
      Can be null for static methods.
      args - The arguments to pass to the method.
      Returns:
      The results of the method invocation.
      Throws:
      ExecutableException - Exception occurred on invoked constructor/method/field.
    • is

      public boolean is(ElementFlag flag)
      Description copied from class: ExecutableInfo
      Returns true if all specified flags are applicable to this method.
      Overrides:
      is in class ExecutableInfo
      Parameters:
      flag - The flag to test for.
      Returns:
      true if all specified flags are applicable to this method.
    • isBridge

      public boolean isBridge()
      Returns true if this method is a bridge method.
      Returns:
      true if this method is a bridge method.
    • isDefault

      public boolean isDefault()
      Returns true if this method is a default method (Java 8+ interface default method).

      Same as calling Method.isDefault().

      A default method is a public non-abstract instance method (i.e., non-static method with a body) declared in an interface.

      Example:

      // For interface: interface MyInterface { default String getName() { return "default"; } } MethodInfo mi = ClassInfo.of(MyInterface.class).getMethod("getName"); if (mi.isDefault()) { // This is a default interface method }

      Returns:
      true if this method is a default method.
      See Also:
    • matches

      public boolean matches(MethodInfo m)
      Returns true if this method matches the specified method by name and parameter types.
      Parameters:
      m - The method to compare against.
      Returns:
      true if this method has the same name and parameter types as the specified method.