MethodQuery.java
package com.github.dakusui.pcond.core.refl;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import static com.github.dakusui.pcond.core.refl.ReflUtils.replacePlaceHolderWithActualArgument;
import static com.github.dakusui.pcond.internals.InternalChecks.requireArgument;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
/**
* An interface that models a query to specify a method.
*/
public interface MethodQuery {
boolean isStatic();
Object targetObject();
Class<?> targetClass();
String methodName();
Object[] arguments();
/**
* Returns a string that describes this object.
*
* @return A description of this object.
*/
String describe();
default MethodQuery bindActualArguments(Predicate<Object> isPlaceHolder, Function<Object, Object> replace) {
Function<Object, Object> argReplacer = object -> replacePlaceHolderWithActualArgument(object, isPlaceHolder, replace);
Object targetObject = argReplacer.apply(this.targetObject());
return create(
this.isStatic(),
targetObject,
this.isStatic() ? this.targetClass() : targetObject.getClass(),
this.methodName(),
Arrays.stream(this.arguments()).map(argReplacer).toArray());
}
static MethodQuery instanceMethod(Object targetObject, String methodName, Object... arguments) {
return create(false, requireNonNull(targetObject), ReflUtils.targetTypeOf(targetObject), methodName, arguments);
}
/**
* Create a `MethodQuery` object to search matching static methods.
*
* @param targetClass A class from which a method is searched.
* @param methodName A name of a method to be searched.
* @param arguments Argument values;
* @return A `MethodQuery` object.
*/
static MethodQuery classMethod(Class<?> targetClass, String methodName, Object... arguments) {
return create(true, null, targetClass, methodName, arguments);
}
static MethodQuery create(boolean isStatic, Object targetObject, Class<?> targetClass, String methodName, Object[] arguments) {
requireNonNull(targetClass);
requireNonNull(arguments);
requireNonNull(methodName);
if (isStatic)
requireArgument(targetObject, Objects::isNull, () -> "targetObject must be null when isStatic is true.");
else {
requireNonNull(targetObject);
requireArgument(targetObject, v -> targetClass.isAssignableFrom(v.getClass()), () -> format("Incompatible object '%s' was given it needs to be assignable to '%s'.", targetObject, targetClass.getName()));
}
return new MethodQuery() {
@Override
public boolean isStatic() {
return isStatic;
}
@Override
public Object targetObject() {
return targetObject;
}
@Override
public String methodName() {
return methodName;
}
@Override
public Class<?> targetClass() {
return targetClass;
}
@Override
public Object[] arguments() {
return arguments;
}
@Override
public String describe() {
Function<Object, String> parameterFormatter = s -> "<" + s + ">";
return format("%s.%s(%s)",
isStatic ?
targetClass.getName() :
parameterFormatter.apply(targetObject),
methodName,
Arrays.stream(arguments)
.map(parameterFormatter)
.collect(joining(",")));
}
};
}
}