package net.tomatentum.cutin.method; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; import net.tomatentum.cutin.ReflectedMethodFactory; import net.tomatentum.cutin.container.MethodContainer; import net.tomatentum.cutin.util.ReflectionUtil; public class BestCandidateMethod extends ReflectedMethod { private String methodName; private I identifier; private List additionalParameters; public BestCandidateMethod(String methodName, Object containingObject, I identifier, Object... additionalParameters) { super(getMethod(containingObject, methodName), containingObject); this.methodName = methodName; this.identifier = identifier; this.additionalParameters = Arrays.asList(additionalParameters); } public BestCandidateMethod(String methodName, Object containingObject, Object... additionalParameters) { super(getMethod(containingObject, methodName), containingObject); this.methodName = methodName; this.identifier = null; this.additionalParameters = Arrays.asList(additionalParameters); } @Override public Object getParameter(Object context, int index) { return additionalParameters.get(index); } @Override public I identifier() { return this.identifier; } @Override public Object run(C context) { Method[] methods = Arrays.stream(containingObject.getClass().getDeclaredMethods()) .filter(x -> x.getName().equals(methodName)) .filter(x -> !x.isBridge()) .toArray(Method[]::new); Class[] parameters = Stream.concat( Stream.of(context.getClass()), additionalParameters.stream().map(Object::getClass) ).toArray(Class[]::new); super.method = ReflectionUtil.getMostSpecificMethod(methods, parameters); return super.run(context); } private static Method getMethod(Object containingMethod, String methodName) { return Arrays.stream(containingMethod.getClass().getDeclaredMethods()) .filter(m -> m.getName().equals(methodName)) .findFirst().orElse(null); } //TODO add result Doc based Parser (which run before produce) public void identifier(I identifier) { this.identifier = identifier; } @Override public boolean equals(Object obj) { if (obj instanceof BestCandidateMethod bcMethod) { return this.containingObject().getClass().equals(bcMethod.containingObject().getClass()) && this.methodName.equals(bcMethod.methodName); } return false; } @Override public int hashCode() { return Objects.hash(containingObject.getClass(), methodName); } public abstract static class Factory implements ReflectedMethodFactory.Factory { private MethodContainer methodContainer; private String methodName; private Object[] additionalParameters; protected Factory(MethodContainer methodContainer, String methodName, Object... additionalParameters) { this.methodContainer = methodContainer; this.methodName = methodName; this.additionalParameters = additionalParameters; } @Override public Optional> produce(Method method, Object containingObject) { BestCandidateMethod bcMethod = new BestCandidateMethod<>( methodName, containingObject, additionalParameters); if (methodContainer.methods().contains(bcMethod)) return Optional.empty(); return Optional.of(bcMethod); } } }