package com.github.aesteve.vertx.nubes.handlers; import com.github.aesteve.vertx.nubes.Config; import com.github.aesteve.vertx.nubes.exceptions.params.WrongParameterException; import com.github.aesteve.vertx.nubes.reflections.injectors.annot.AnnotatedParamInjector; import com.github.aesteve.vertx.nubes.reflections.injectors.annot.AnnotatedParamInjectorRegistry; import com.github.aesteve.vertx.nubes.reflections.injectors.typed.ParamInjector; import com.github.aesteve.vertx.nubes.reflections.injectors.typed.TypedParamInjectorRegistry; import io.vertx.core.Handler; import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.RoutingContext; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; public abstract class AbstractMethodInvocationHandler<T> implements Handler<RoutingContext> { protected final Method method; protected final Object instance; protected final boolean hasNext; protected final BiConsumer<RoutingContext, T> returnHandler; protected final boolean returnsSomething; private final Config config; private final Parameter[] parameters; protected boolean usesRoutingContext; protected boolean usesHttpResponse; protected AbstractMethodInvocationHandler(Object instance, Method method, Config config, boolean hasNext, BiConsumer<RoutingContext, T> returnHandler) { this.method = method; returnsSomething = !method.getReturnType().equals(Void.TYPE); this.hasNext = hasNext; parameters = method.getParameters(); for (Parameter param : parameters) { Class<?> paramType = param.getType(); if (paramType.equals(RoutingContext.class)) { usesRoutingContext = true; } if (paramType.equals(HttpServerResponse.class)) { usesHttpResponse = true; } } this.config = config; this.instance = instance; this.returnHandler = returnHandler; } @Override abstract public void handle(RoutingContext routingContext); protected Object[] getParameters(RoutingContext routingContext) throws WrongParameterException { List<Object> params = new ArrayList<>(); for (Parameter param : parameters) { Object paramInstance = getParameterInstance(routingContext, param.getAnnotations(), param.getType(), param.getName()); params.add(paramInstance); } return params.toArray(); } @SuppressWarnings({"rawtypes", "unchecked"}) private Object getParameterInstance(RoutingContext context, Annotation[] annotations, Class<?> parameterClass, String paramName) throws WrongParameterException { final TypedParamInjectorRegistry typeInjectors = config.getTypeInjectors(); if (annotations.length == 0) { // rely on type final ParamInjector<?> injector = typeInjectors.getInjector(parameterClass); if (injector == null) { return null; } return injector.resolve(context); } if (annotations.length > 1) { throw new IllegalArgumentException("Every parameter should only have ONE annotation"); } final Annotation annotation = annotations[0]; // rely on annotation final AnnotatedParamInjectorRegistry annotatedInjectors = config.getAnnotatedInjectors(); final AnnotatedParamInjector injector = annotatedInjectors.getInjector(annotation.annotationType()); if (injector == null) { return null; } return injector.resolve(context, annotation, paramName, parameterClass); } }