Class MethodInfo

All Implemented Interfaces:
Comparable<MethodInfo>, Annotatable

public final 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. Must not be null.
      inner - The method being wrapped. Must not be null.
  • 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 @Marshalled annotations, this method returns each @Marshalled 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 @Marshalled annotations on this method and overridden methods Stream<AnnotationInfo<Bean>> beans = methodInfo.getAnnotations(Bean.class); // If method has @Beans(), both individual @Marshalled instances are returned

      Type Parameters:
      A - The annotation type.
      Parameters:
      type - The annotation type to filter by. Must not be null.
      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.
    • isGetter

      public boolean isGetter()
      Returns true if this method follows the Java Bean getter convention.

      A getter is a public no-argument method whose name starts with get (with a non-void return type) or is (with a boolean/Boolean return type).

      Returns:
      true if this method is a bean getter.
    • isSetter

      public boolean isSetter()
      Returns true if this method follows the Java Bean setter convention.

      A setter is a method whose name starts with set and accepts exactly one argument.

      Returns:
      true if this method is a bean 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.
    • hasParameter

      public boolean hasParameter(Object parameter)
      Returns true if this method has a parameter that can accept the specified object.
      Parameters:
      parameter - The parameter object to check for.
      Returns:
      true if this method has at least one parameter that can accept the specified object.
    • 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.

      If the underlying method is static, then the specified obj argument is ignored. It may be null.

      If the number of formal parameters required by the underlying method is 0, the supplied args array may be of length 0 or null.

      Type Parameters:
      T - The method return type.
      Parameters:
      obj - The object the underlying method is invoked from. Can be null for static methods.
      args - The arguments used for the method call. Can be null or empty for methods with no parameters.
      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.
    • getMissingParameterTypes

      public String getMissingParameterTypes(BeanStore beanStore, Object... otherBeans)
      Returns comma-delimited list of missing parameter types.

      Analyzes the parameters of this method and checks if all required beans are available in the bean store or in the otherBeans parameter.

      The following parameter types are considered optional and are not checked:

      • Parameters of type Optional<T>
      • Parameters of type T[], List<T>, Set<T>, or Map<String,T>

      If a parameter has a @Named or @Qualifier annotation, the method checks for a bean with that specific name in the bean store. Otherwise, it checks for an unnamed bean of the parameter type in the bean store, and if not found, checks the otherBeans parameter.

      Parameters:
      beanStore - The bean store to check for beans.
      otherBeans - Optional additional bean instances to check if not found in the bean store. These are checked after the bean store but before marking the parameter as missing.
      Returns:
      A comma-delimited, sorted list of missing parameter types (e.g., "String,Integer"), or null if all required parameters are available.
    • canResolveAllParameters

      public boolean canResolveAllParameters(BeanStore beanStore, Object... otherBeans)
      Checks if all method parameters can be resolved.

      This method performs the same checks as getMissingParameterTypes(BeanStore, Object...) but returns a boolean instead of a list of missing types.

      The following parameter types are considered optional and are not checked:

      • Parameters of type Optional<T>
      • Parameters of type T[], List<T>, Set<T>, or Map<String,T>

      If a parameter has a @Named or @Qualifier annotation, the method checks for a bean with that specific name in the bean store. Otherwise, it checks for an unnamed bean of the parameter type in the bean store, and if not found, checks the otherBeans parameter.

      Parameters:
      beanStore - The bean store to check for beans.
      otherBeans - Optional additional bean instances to check if not found in the bean store. These are checked after the bean store but before marking the parameter as missing.
      Returns:
      true if all required parameters are available in the bean store or otherBeans, false otherwise.
    • inject

      public <T> T inject(BeanStore beanStore, Object bean, Object... otherBeans)
      Resolves parameters from the bean store and invokes the method.

      For each parameter in the method, this method:

      • If the parameter is a collection/array/map type, collects all beans of the element type.
      • Otherwise, looks up a single bean by type and optional qualifier name in the bean store.
      • If not found in the bean store, checks the otherBeans parameter.
      Parameter Resolution:
      • Single beans - Resolved using BeanStore.getBean(Class) or BeanStore.getBean(Class, String). If not found, checks otherBeans for a compatible instance. Throws ExecutableException if not found in either location.
      • Optional beans - Wrapped in Optional, or Optional.empty() if not found. Never throws an exception.
      • Arrays - All beans of the element type are collected into an array (may be empty). Never throws an exception.
      • Lists - All beans of the element type are collected into a List (may be empty). Never throws an exception.
      • Sets - All beans of the element type are collected into a LinkedHashSet (may be empty). Never throws an exception.
      • Maps - All beans of the value type are collected into a LinkedHashMap keyed by bean name (may be empty). Unnamed beans use an empty string as the key. Never throws an exception.

      The bean parameter is the object instance on which to invoke the method (or null for static methods).

      Type Parameters:
      T - The return type of the method.
      Parameters:
      beanStore - The bean store to resolve parameters from.
      bean - The object instance on which to invoke the method (or null for static methods).
      otherBeans - Optional additional bean instances to use if not found in the bean store.
      Returns:
      The result of invoking the method.
      Throws:
      ExecutableException - If the method cannot be invoked or parameter resolution fails.