Class PatternMatchingMethodInvoker<ARGUMENT_COMMON_ROOT_TYPE>

java.lang.Object
dk.cloudcreate.essentials.shared.reflection.invocation.PatternMatchingMethodInvoker<ARGUMENT_COMMON_ROOT_TYPE>
Type Parameters:
ARGUMENT_COMMON_ROOT_TYPE - The method argument common root type (i.e. a common superclass or common interface) for the argument-type that we're performing pattern matching on.
If there isn't a common root type, then you can specify Object instead

Example: Within a single class we have placed a set methods that can handle OrderEvent's, such as OrderCreated, OrderShipped, OrderAccepted, etc.
In this case OrderEvent will be our ARGUMENT_ROOT_TYPE as it forms the root of the type hierarchy.


public final class PatternMatchingMethodInvoker<ARGUMENT_COMMON_ROOT_TYPE> extends Object
The purpose of the PatternMatchingMethodInvoker is to support pattern matching a set of typed methods against a concrete argument and have the method(s) that match the type resolved by the MethodPatternMatcher.resolveInvocationArgumentTypeFromObject(Object) will be invoked by the MethodPatternMatcher.invokeMethod(Method, Object, Object, Class) with the argument

Example: Say we have a single class we have placed a set methods that can handle OrderEvent's, such as OrderCreated, OrderShipped, OrderAccepted, etc.
In this case OrderEvent will be our ARGUMENT_ROOT_TYPE as it forms the root of the type hierarchy.

After deciding on the ARGUMENT_ROOT_TYPE we need to determine how to match the methods.
This involves several parts: 1. Method Pattern using MethodPatternMatcher.isInvokableMethod(Method) Example of methods patterns that matches the intention of this class:
  • Annotation based - where an annotation marks the methods that should be matched:
          @EventHandler
           private void some_name_that_we_do_not_care_about(OrderCreated t, ...) { ... }
    
          @EventHandler
           private void some_name_that_we_do_not_care_about(OrderAccepted t, ...) { ... }
         
  • Name based - where a specific name, e.g. "on" in the example below, the methods that should be matched:
          private void on(OrderCreated t) { ... }
    
          private void on(OrderAccepted t) { ... }
         
  • Or some other patterns that you're interested in supporting
2. Resolve the concreted Argument Type the method support accepts using MethodPatternMatcher.resolveInvocationArgumentTypeFromMethodDefinition(Method) 3. Discover all methods matching the argument instance supplied to the invoke(Object)/invoke(Object, NoMatchingMethodsHandler) methods After we've filtered out and found the methods that match our pattern, next phase is to figure out what methods match a concrete argument instance.
Example: Let's say the argument object is an instance of OrderAccepted and we're matching against the following methods
      @EventHandler
       private void method1(OrderEvent t) { ... }

      @EventHandler
       private void method2(OrderShipped t) { ... }

      @EventHandler
       private void method3(OrderAccepted t) { ... }
     

In this case both method1 and method3 match on type of the argument instance (OrderAccepted), because OrderEvent (of method1) match by hierarchy, and OrderAccepted (of method3) match directly by type.

4. Choose which method(s) to invoke Next step is to check the InvocationStrategy to determine which method(s) to invoke based on the concrete argument instance supplied to the invoke(Object)/invoke(Object, NoMatchingMethodsHandler) methods MethodPatternMatcher For some methods, it's not necessarily the first argument that decides what argument-type the method supports and the method may need to be called with multiple arguments and not just one.
E.g. when handling enveloped types (such as Messages that encapsulate a payload) we may want to match methods against the message' payload type instead of the message type
What methods is a candidate for matching, what type a given method supports and how the method is invoked is determined by MethodPatternMatcher.
For more simple cases the SingleArgumentAnnotatedMethodPatternMatcher provides a good default implementation. Logging Using a setup where the PatternMatchingMethodInvoker is invoking methods on an instance of dk.cloudcreate.handlers.OrderEventsHandler

 var patternMatchingInvoker = new PatternMatchingMethodInvoker<>(new dk.cloudcreate.handlers.OrderEventsHandler(),
                                                                 new SingleArgumentAnnotatedMethodPatternMatcher(EventHandler.class,
                                                                                                                 OrderEvent.class),
                                                                 InvocationStrategy.InvokeMostSpecificTypeMatched,
                                                                 Optional.empty());
 
and you want PatternMatchingMethodInvoker logging then you should set the logging level for dk.cloudcreate.handlers.OrderEventsHandler to TRACE

See Also: