Class MethodInvocation<T>

  • Type Parameters:
    T - Type of method receiver (i.e. this)
    All Implemented Interfaces:
    Invocation

    public final class MethodInvocation<T>
    extends Object
    implements Invocation
    Capture of a information needed to invoke a method.

    This class collects and mimics arguments received by different proxy frameworks when method is intercepted on proxy object, represents it in uniform fashion and allows some manipulations. Instances of this class can be also constructed synthetically, as if the call was made but intercepted before execution.

    This class handles three elements of a call: Method that was called, a receiver, that is object on which method was called, and arguments that were passed with the call. Receiver can be omitted, if the method is static.

    There are two most important methods on this class: invoke() which will execute the method with specified arguments and receiver, and return result or throw an exception. The other method is decompose(org.perfectable.introspection.proxy.MethodInvocation.Decomposer<? super T, R>) which allows introspection of structure of this invocation.

    Objects of this class are unmodifiable, that is methods of this class that would change the object actually produce new changed object. It is not immutable, because both receiver and arguments passed can, and often are, mutable.

    • Method Detail

      • intercepted

        public static <T> MethodInvocation<T> intercepted​(Method method,
                                                          @Nullable
                                                          T receiver,
                                                          @Nullable
                                                          Object... arguments)
        Create invocation that was intercepted from proxy mechanism.

        This method assumes that if method is vararg, and requires X non-vararg parameters, the arguments passed here contains exactly X+1 elements, where X one are the non-vararg arguments that are compatible with non-vararg parameter type, and the last element is an array of elements of the vararg type. This is how the method call is represented in runtime for varargs. This method will 'unroll' the last array argument and create invocation that has flat arguments array.

        For non-varargs method, this method is identical to of(java.lang.reflect.Method, T, java.lang.Object...), i.e. arguments must be a flat array with element count exactly equal to method parameter count, and with compatible types.

        Type Parameters:
        T - type of receiver
        Parameters:
        method - method that was/will be called on invocation
        receiver - receiver of the method call (i.e. this)
        arguments - arguments in a runtime representation
        Returns:
        method invocation comprised from passed arguments
        Throws:
        IllegalArgumentException - when method invocation is illegal and will not succeed: ex. method is static and receiver was provided (or other way around), receiver is of wrong type for the provided method, or arguments are not matching method parameter types.
      • of

        public static <T> MethodInvocation<T> of​(Method method,
                                                 @Nullable
                                                 T receiver,
                                                 Object... arguments)
        Create synthetic invocation from scratch.

        This method assumes that if method is vararg, and requires X non-vararg parameters, arguments contain at least X elements, where each of these elements is compatible with corresponding parameter of the method, and any amount of elements that are compatible with the variable parameter of the method.

        For non-varargs method, this method expects an array with element count exactly equal to method parameter count, and with compatible types.

        Type Parameters:
        T - type of receiver
        Parameters:
        method - method that was/will be called on invocation
        receiver - receiver of the method call (i.e. this)
        arguments - arguments in a source representation
        Returns:
        method invocation comprised from passed arguments
        Throws:
        IllegalArgumentException - when method invocation is illegal and will not succeed: ex. method is static and receiver was provided (or other way around), receiver is of wrong type for the provided method, or arguments are not matching method parameter types.
      • invoke

        @CanIgnoreReturnValue
        @Nullable
        public Object invoke()
                      throws Throwable
        Executes the configured invocation.
        Specified by:
        invoke in interface Invocation
        Returns:
        result of non-throwing invocation. If the method was void, the result will be null.
        Throws:
        Throwable - result of throwing invocation. This will be exactly the exception that method thrown.
      • decompose

        @CanIgnoreReturnValue
        public <R> R decompose​(MethodInvocation.Decomposer<? super T,​R> decomposer)
        Decomposes the invocation to its parts.

        This method allows to transform this invocation by its parts into other object.

        For example, decomposition might produce log message of method called:

             Decomposer<Object, String> stringifingDecomposer = (method, receiver, arguments) ->
                 String.format("Method %s was called on %s with %s", method, receiver, arguments);
             LOGGER.debug(invocation.decompose(stringifingDecomposer))
         

        Another example: decomposer might substitute invocation method for another one:

             Decomposer<Object, MethodInvocation<?>> replacingDecomposer = (method, receiver, arguments) ->
                 MethodInvocation.of(anotherMethod, receiver, arguments);
             MethodInvocation<?> replacedMethodInvocation = invocation.decompose(replacingDecomposer))
             return replacedMethodInvocation.invoke();
         
        Type Parameters:
        R - return type of decomposition
        Parameters:
        decomposer - decomposer to use for this invocation
        Returns:
        whatever decomposer returned on its MethodInvocation.Decomposer.decompose(java.lang.reflect.Method, T, java.lang.Object...) call
      • withMethod

        public MethodInvocation<T> withMethod​(Method newMethod)
        Creates new invocation with replaced method.

        New method is checked for compatibility with both receiver and arguments.

        Parameters:
        newMethod - another method to be used
        Returns:
        new invocation with new method, same receiver and same arguments
        Throws:
        IllegalArgumentException - when new method is incompatible with receiver or arguments in any way
      • withReceiver

        public <X extends TMethodInvocation<X> withReceiver​(X newReceiver)
        Creates new invocation with replaced receiver.

        New receiver is checked for compatibility with method.

        Type Parameters:
        X - extension type of the receiver, to allow concretization of result
        Parameters:
        newReceiver - another receiver to be used
        Returns:
        new invocation with same method, new receiver and same arguments
        Throws:
        IllegalArgumentException - when new receiver is incompatible with method
      • withArguments

        public MethodInvocation<T> withArguments​(Object... newArguments)
        Creates new invocation with replaced arguments.

        New arguments is checked for compatibility with method.

        Parameters:
        newArguments - new arguments to be used
        Returns:
        new invocation with same method, same receiver and new arguments
        Throws:
        IllegalArgumentException - when new arguments is incompatible with method
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class Object