Call.java
package Hoot.Runtime.Behaviors;
import java.util.*;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import Hoot.Runtime.Names.Keyword;
import Hoot.Runtime.Names.Selector;
import static Hoot.Runtime.Functions.Utils.*;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
/**
* Describes a method call.
* @author nik <nikboyd@sonic.net>
* @see "Copyright 2010,2024 Nikolas S Boyd."
* @see "Permission is granted to copy this work provided this copyright statement is retained in all copies."
*/
public interface Call {
default Object receiver() { return null; }
default String methodName() { return getClass().getCanonicalName(); }
default String selectedName() { return Keyword.with(methodName()).methodName(); }
default Class<?> selectedClass() { return Selector.named(methodName()).toClass(); }
static final Class VoidClass = void.class;
default Class<?> receiverType() {
return hasNo(receiver())? VoidClass:
Class.class.isInstance(receiver())? (Class)receiver():
receiver().getClass(); }
static final Object[] NoArgs = {};
default Object[] argValues() { return unwrap(argumentValues(), NoArgs); }
default List<Object> argumentValues() { return new ArrayList<>(); }
static final Class[] NoTypes = {};
default Class[] argTypes() { return unwrap(argumentTypes(), NoTypes); }
default List<Class<?>> argumentTypes() {
return map(argumentValues(), arg -> arg.getClass()); }
default Method findMethod() {
return MethodUtils.getMatchingAccessibleMethod(
receiverType(), selectedName(), argTypes()); }
default Constructor findConstructor() {
return ConstructorUtils.getAccessibleConstructor(
constructorType(), argTypes()); }
default Class<?> constructorType() {
if (hasOne(methodName())) return selectedClass();
reportMissingReceiver();
return null;
}
default Object callMethod() {
try {
if (VoidClass == receiverType()) {
Constructor c = findConstructor(); if (hasNo(c)) return null;
return c.newInstance(argValues());
}
else {
Method m = findMethod(); if (hasNo(m)) return null;
return m.invoke(receiver(), argValues());
}
}
catch (Exception ex) {
return null;
}
}
default void reportMissingReceiver() {
throw new IllegalArgumentException("expected a Class or TypeDescription"); }
} // Call