content: package com.github.aesteve.vertx.nubes.reflections;
  
  import com.github.aesteve.vertx.nubes.Config;
  import com.github.aesteve.vertx.nubes.annotations.Controller;
  import com.github.aesteve.vertx.nubes.annotations.File;
  import com.github.aesteve.vertx.nubes.annotations.View;
  import com.github.aesteve.vertx.nubes.annotations.sockjs.SockJS;
  import com.github.aesteve.vertx.nubes.context.FileResolver;
  import com.github.aesteve.vertx.nubes.context.ViewResolver;
  import com.github.aesteve.vertx.nubes.reflections.annotations.ReflectionProviderHelper;
  import com.github.aesteve.vertx.nubes.reflections.factories.AuthenticationFactory;
  import com.github.aesteve.vertx.nubes.reflections.visitors.ControllerVisitor;
  import com.github.aesteve.vertx.nubes.routing.MVCRoute;
  import io.vertx.core.VertxException;
  import io.vertx.ext.web.Router;
  import io.vertx.ext.web.RoutingContext;
  import org.reflections.Reflections;
  
  import java.lang.annotation.Annotation;
  import java.util.*;
  import java.util.function.BiConsumer;
  
  public class RouteFactory implements HandlerFactory {
  
    private final Router router;
    private final Config config;
    private final AuthenticationFactory authFactory;
    private final RouteRegistry routeRegistry;
    private Map<Class<? extends Annotation>, BiConsumer<RoutingContext, ?>> returnHandlers;
  
    public RouteFactory(Router router, Config config) {
      this.router = router;
      this.config = config;
      routeRegistry = new RouteRegistry();
      authFactory = new AuthenticationFactory(config);
      createReturnHandlers();
    }
  
    private void createReturnHandlers() {
      returnHandlers = new HashMap<>();
      returnHandlers.put(View.class, (context, res) -> {
        if (res instanceof String) {
          ViewResolver.resolve(context, (String) res);
        } else if (res instanceof Map) {
          @SuppressWarnings("unchecked") // we have to...
              Map<? extends String, ?> mapRes = (Map<? extends String, ?>) res;
          context.data().putAll(mapRes);
        }
      });
      returnHandlers.put(File.class, (context, res) -> FileResolver.resolve(context, (String) res));
    }
  
    @Override
    public void createHandlers() {
      List<MVCRoute> routes = extractRoutesFromControllers();
      routes.stream().filter(MVCRoute::isEnabled).forEach(route -> route.attachHandlersToRouter(router));
    }
  
    private List<MVCRoute> extractRoutesFromControllers() {
      List<MVCRoute> routes = new ArrayList<>();
      config.forEachControllerPackage(controllerPackage -> {
        Set<Class<?>> controllers = ReflectionProviderHelper.getAnnotationProcessor(config, controllerPackage).getClassesTypesAnnotatedWith(Controller.class);
        controllers.forEach(controller -> routes.addAll(extractRoutesFromController(controller)));
      });
      return routes;
    }
  
    private List<MVCRoute> extractRoutesFromController(Class<?> controller) {
      try {
        ControllerVisitor<?> visitor = new ControllerVisitor<>(controller, config, router, authFactory, routeRegistry, returnHandlers);
        return visitor.visit();
      } catch (IllegalAccessException | InstantiationException e) {
        throw new VertxException(e);
      }
    }
  
  }
  