content: package com.github.aesteve.vertx.nubes.handlers.impl;
  
  import com.github.aesteve.vertx.nubes.Config;
  import com.github.aesteve.vertx.nubes.exceptions.params.WrongParameterException;
  import com.github.aesteve.vertx.nubes.handlers.AbstractMethodInvocationHandler;
  import com.github.aesteve.vertx.nubes.marshallers.Payload;
  import io.vertx.core.http.HttpServerResponse;
  import io.vertx.core.logging.Logger;
  import io.vertx.core.logging.LoggerFactory;
  import io.vertx.ext.web.RoutingContext;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.function.BiConsumer;
  
  public class DefaultMethodInvocationHandler<T> extends AbstractMethodInvocationHandler<T> {
  
    private static final Logger LOG = LoggerFactory.getLogger(DefaultMethodInvocationHandler.class);
  
    public DefaultMethodInvocationHandler(Object instance, Method method, Config config, boolean hasNext, BiConsumer<RoutingContext, T> returnHandler) {
      super(instance, method, config, hasNext, returnHandler);
    }
  
    @Override
    public void handle(RoutingContext routingContext) {
      if (routingContext.response().ended()) {
        return;
      }
      if (routingContext.failed()) {
        return;
      }
      Object[] parameters;
      try {
        parameters = getParameters(routingContext);
      } catch (WrongParameterException e) { //NOSONAR
        DefaultErrorHandler.badRequest(routingContext, e.getMessage());
        return;
      }
      try {
        handleInvokation(routingContext, parameters);
      } catch (InvocationTargetException | IllegalAccessException ite) {
        LOG.error(ite);
        routingContext.fail(ite.getCause());
      }
    }
  
    @SuppressWarnings("unchecked")
    private void handleInvokation(RoutingContext routingContext, Object[] parameters) throws IllegalAccessException, InvocationTargetException {
      final T returned = (T) method.invoke(instance, parameters);
      if (returnsSomething) {
        handleMethodReturn(routingContext, returned);
      }
      if (!usesRoutingContext && hasNext) { // cannot call context.next(), assume the method is sync
        routingContext.next();
      }
      if (!usesRoutingContext && !usesHttpResponse && !hasNext) {
        sendResponse(routingContext);
      }
    }
  
    private void sendResponse(RoutingContext routingContext) {
      HttpServerResponse response = routingContext.response();
      try {
        response.setStatusCode(204);
        response.end();
      } catch (IllegalStateException ise) { //NOSONAR
        // do not log for the user, this means the response has already been written
        // that'd mean something is wrong with the **framework** not users' code
        routingContext.next();
      }
    }
  
    private void handleMethodReturn(RoutingContext routingContext, T returned) {
      final boolean contentTypeSet = routingContext.get(ContentTypeProcessor.BEST_CONTENT_TYPE) != null;
      if (returnHandler != null) {
        returnHandler.accept(routingContext, returned);
      } else if (hasNext && contentTypeSet) {
        // try to set as Payload
        Payload<Object> payload = routingContext.get(Payload.DATA_ATTR);
        if (payload == null) {
          payload = new Payload<>();
          routingContext.put(Payload.DATA_ATTR, payload);
        }
        payload.set(returned);
      } else if (returned instanceof String) {
        routingContext.response().end((String) returned);
      }
    }
  }