/** Returns visualized routing rules. */ @Override public String toString() { // Step 1/2: Dump routers and anyMethodRouter in order final int numRoutes = size(); final List<String> methods = new ArrayList<String>(numRoutes); final List<String> paths = new ArrayList<String>(numRoutes); final List<String> targets = new ArrayList<String>(numRoutes); // For router for (Entry<HttpMethod, MethodlessRouter<T>> e : routers.entrySet()) { HttpMethod method = e.getKey(); MethodlessRouter<T> router = e.getValue(); aggregateRoutes(method.toString(), router.first().routes(), methods, paths, targets); aggregateRoutes(method.toString(), router.other().routes(), methods, paths, targets); aggregateRoutes(method.toString(), router.last().routes(), methods, paths, targets); } // For anyMethodRouter aggregateRoutes("*", anyMethodRouter.first().routes(), methods, paths, targets); aggregateRoutes("*", anyMethodRouter.other().routes(), methods, paths, targets); aggregateRoutes("*", anyMethodRouter.last().routes(), methods, paths, targets); // For notFound if (notFound != null) { methods.add("*"); paths.add("*"); targets.add(targetToString(notFound)); } // Step 2/2: Format the List into aligned columns: <method> <path> <target> int maxLengthMethod = maxLength(methods); int maxLengthPath = maxLength(paths); String format = "%-" + maxLengthMethod + "s %-" + maxLengthPath + "s %s\n"; int initialCapacity = (maxLengthMethod + 1 + maxLengthPath + 1 + 20) * methods.size(); StringBuilder b = new StringBuilder(initialCapacity); for (int i = 0; i < methods.size(); i++) { String method = methods.get(i); String path = paths.get(i); String target = targets.get(i); b.append(String.format(format, method, path, target)); } return b.toString(); }