Invocable.java
package space.sunqian.common.invoke;
import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* This interface represents an invocable entity, such as a method, constructor, function, executable task, executable
* scope or other similar entity.
* <p>
* This interface provides two equivalent methods: {@link #invoke(Object, Object...)} which declares an unchecked
* exception, and {@link #invokeChecked(Object, Object...)} which declares a checked exception.
* <p>
* The thread-safety of this interface depends on invocable entity it holds.
*
* @author sunqian
*/
public interface Invocable {
/**
* Returns an empty {@link Invocable} which has no effect and always returns {@code null}.
*
* @return an empty {@link Invocable} which has no effect and always returns {@code null}
*/
static @Nonnull Invocable empty() {
return ByOthers.EmptyInvoker.INST;
}
/**
* Returns a new {@link Invocable} represents the specified method, using recommended implementation in current
* environment.
*
* @param method the specified method
* @return a new {@link Invocable} represents the specified method
*/
static @Nonnull Invocable of(@Nonnull Method method) {
return of(method, InvocationMode.recommended(method));
}
/**
* Returns a new {@link Invocable} represents the specified constructor, using recommended implementation in current
* environment.
*
* @param constructor the specified constructor
* @return a new {@link Invocable} represents the specified constructor
*/
static @Nonnull Invocable of(@Nonnull Constructor<?> constructor) {
return of(constructor, InvocationMode.recommended(constructor));
}
/**
* Returns a new {@link Invocable} represents the specified method handle.
*
* @param handle the specified method handle
* @param isStatic specifies whether the method handle is for a static method, constructor, or similar
* @return a new {@link Invocable} represents the specified method handle
*/
static @Nonnull Invocable of(@Nonnull MethodHandle handle, boolean isStatic) {
return ByMethodHandle.newInvocable(handle, isStatic);
}
/**
* Returns a new {@link Invocable} represents the specified method, using specified implementation.
*
* @param method the specified method
* @param mode specifies the implementation of the returned instance
* @return a new {@link Invocable} represents the specified method
*/
static @Nonnull Invocable of(@Nonnull Method method, @Nonnull InvocationMode mode) {
switch (mode) {
case METHOD_HANDLE:
return ByMethodHandle.newInvocable(method);
case ASM:
return ByAsm.newInvocable(method);
default:
return ByReflection.newInvocable(method);
}
}
/**
* Returns a new {@link Invocable} represents the specified constructor, using specified implementation.
*
* @param constructor the specified constructor
* @param mode specifies the implementation of the returned instance
* @return a new {@link Invocable} represents the specified constructor
*/
static @Nonnull Invocable of(@Nonnull Constructor<?> constructor, @Nonnull InvocationMode mode) {
switch (mode) {
case METHOD_HANDLE:
return ByMethodHandle.newInvocable(constructor);
case ASM:
return ByAsm.newInvocable(constructor);
default:
return ByReflection.newInvocable(constructor);
}
}
/**
* Executes this invocable entity with an instance and the invocation arguments. The instance typically represents
* the owner object of a method or the scope of '{@code this}', and the arguments typically represent the actual
* arguments passed to the method or function. The instance can be {@code null} if this entity is a static method,
* constructor, or other similar entity.
* <p>
* This method only throws {@link InvocationException} which wraps any other {@link Throwable}, the original cause
* can be retrieved by {@link InvocationException#getCause()}. This method is equivalent to:
* <pre>{@code
* try {
* return invokeChecked(inst, args);
* } catch (Throwable e) {
* throw new InvocationException(e);
* }
* }</pre>
*
* @param inst the instance
* @param args the invocation arguments
* @return the invocation result
* @throws InvocationException for any {@link Throwable}
*/
default Object invoke(
@Nullable Object inst, Object @Nonnull ... args
) throws InvocationException {
try {
return invokeChecked(inst, args);
} catch (Throwable e) {
throw new InvocationException(e);
}
}
/**
* Executes this invocable entity with an instance and the invocation arguments. The instance typically represents
* the owner object of a method or the scope of '{@code this}', and the arguments typically represent the actual
* arguments passed to the method or function. The instance can be {@code null} if this entity is a static method,
* constructor, or other similar entity.
* <p>
* This method directly throws any exception thrown from the underlying invocation.
*
* @param inst the instance
* @param args the invocation arguments
* @return the invocation result
* @throws Throwable directly throws any exception thrown from the underlying invocation
*/
Object invokeChecked(@Nullable Object inst, Object @Nonnull ... args) throws Throwable;
}