Class MethodInvocation<T>
- java.lang.Object
-
- org.perfectable.introspection.proxy.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 isdecompose(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.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interface
MethodInvocation.Decomposer<T,R>
Interface that allows decomposition of the invocation.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description <R> R
decompose(MethodInvocation.Decomposer<? super T,R> decomposer)
Decomposes the invocation to its parts.boolean
equals(Object obj)
int
hashCode()
static <T> MethodInvocation<T>
intercepted(Method method, T receiver, Object... arguments)
Create invocation that was intercepted from proxy mechanism.Object
invoke()
Executes the configured invocation.static <T> MethodInvocation<T>
of(Method method, T receiver, Object... arguments)
Create synthetic invocation from scratch.MethodInvocation<T>
withArguments(Object... newArguments)
Creates new invocation with replaced arguments.MethodInvocation<T>
withMethod(Method newMethod)
Creates new invocation with replaced method.<X extends T>
MethodInvocation<X>withReceiver(X newReceiver)
Creates new invocation with replaced receiver.
-
-
-
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, thearguments
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 toof(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 invocationreceiver
- 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 invocationreceiver
- 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 interfaceInvocation
- 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 T> MethodInvocation<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
-
-