All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ru.yandex.qatools.camelot.common.AnnotatedMethodDispatcher Maven / Gradle / Ivy
package ru.yandex.qatools.camelot.common;
import ru.yandex.qatools.camelot.error.DispatchException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import static java.lang.String.format;
import static java.util.Arrays.asList;
/**
* @author Ilya Sadykov (mailto: [email protected] )
*/
public class AnnotatedMethodDispatcher {
private final Object instance;
private final MetadataClassInfo cache;
public AnnotatedMethodDispatcher(Object instance, MetadataClassInfo meta) {
this.cache = meta;
this.instance = instance;
}
public Map dispatch(Class extends Annotation> annClass, boolean singleCall, Object... params) throws Exception { //NOSONAR
final List paramTypes = new ArrayList<>();
final List paramList = new ArrayList<>();
for (Object value : params) {
paramTypes.add(value.getClass());
paramList.add(value);
}
if (paramTypes.isEmpty()) {
throw new DispatchException(format("Failed to invoke methods annotated with @%s: parameters are empty!", annClass));
}
final Map called = new HashMap<>();
for (int i = 0; i <= paramTypes.size(); ++i) {
for (int j = paramTypes.size(); j >= i; --j) {
final List typesSubList = paramTypes.subList(i, j);
final Deque typesStack = new ArrayDeque<>();
typesStack.push(typesSubList.toArray(new Class[typesSubList.size()]));
call(annClass, typesStack, paramList.subList(i, j), singleCall, called, 0);
if (singleCall && !called.isEmpty()) {
return called;
}
}
}
return called;
}
protected void call(Class extends Annotation> annClass, Deque typesStack, List params,
boolean singleCall, Map called, int paramIdx) throws Exception { //NOSONAR
try {
if (singleCall && !called.isEmpty()) {
return;
}
List paramTypes = new ArrayList<>();
paramTypes.addAll(asList(typesStack.peek()));
if (paramIdx >= paramTypes.size() || paramTypes.get(paramIdx) == Object.class) {
return;
}
for (Class paramType : cache.getSuperClasses(paramTypes.get(paramIdx))) {
paramTypes.set(paramIdx, paramType);
findSuitableMethodAndCall(annClass, paramTypes, params, singleCall, called);
typesStack.push(paramTypes.toArray(new Class[paramTypes.size()]));
call(annClass, typesStack, params, singleCall, called, paramIdx + 1);
typesStack.pop();
if (singleCall && !called.isEmpty()) {
return;
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
throw wrapThrowableIfRequired(e, e.getCause());
} catch (InvocationTargetException e) {
throw wrapThrowableIfRequired(e, e.getTargetException());
}
}
private Exception wrapThrowableIfRequired(Throwable e, Throwable cause) throws Exception { //NOSONAR
if (cause == null) {
return wrapThrowableIfRequired(e, null);
}
return (cause instanceof Exception) ? (Exception) cause : new Exception(cause);
}
@SuppressWarnings("unchecked")
private void findSuitableMethodAndCall(Class extends Annotation> annClass, List paramTypes, List params,
boolean singleCall, Map called) throws Exception { //NOSONAR
final Class[] mParamTypes = paramTypes.toArray(new Class[paramTypes.size()]);
final Collection methods = cache.getMethodsByParamTypes(annClass, mParamTypes);
for (Method method : methods) {
if (checkMethodParams(method.getParameterTypes(), paramTypes)) {
callMethod(method, paramTypes, params, called);
if (singleCall && !called.isEmpty()) {
return;
}
}
}
}
private void callMethod(Method method, List types, List params, Map called) throws IllegalAccessException, InvocationTargetException {
if (types.size() == method.getParameterTypes().length && !called.containsKey(method)) {
called.put(
method,
method.invoke(instance, params.toArray(new Object[types.size()]))
);
}
}
private boolean checkMethodParams(Class[] paramTypes, List types) {
if (types.size() > paramTypes.length) {
return false;
}
for (int i = 0; i < types.size(); ++i) {
if (!paramTypes[i].equals(types.get(i))) {
return false;
}
}
return true;
}
}