Eine Sache, die mich gerade jetzt am Anfang (wo man viel herumprobiert) bei Ninja stört, ist dass die Routes “zentral” in einer gleichnamigen Klasse gemanaged werden, also etwa so:
public class Routes implements ApplicationRoutes {
@Override
public void init(Router router) {
router.GET().route("/").with(ApplicationController.class, "index");
router.POST().route("/login").with(UserController.class, "login");
// Assets (pictures / javascript)
router.GET().route("/assets/webjars/{fileName: .*}").with(AssetsController.class, "serveWebJars");
router.GET().route("/assets/{fileName: .*}").with(AssetsController.class, "serveStatic");
// Index / Catchall shows index page
router.GET().route("/.*").with(ApplicationController.class, "index");
}
}
Zum einen finde ich “String-als-Methoden-Referenz” ein wenig gewagt, und zum anderen ist es wirklich schwer, Controller, Freemarker-Template und Routes synchron zu halten - drei Stellen sind einfach eine zu viel. Also habe ich einen neuen Ansatz gewählt:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Gets.class)
public @interface Get {
String value();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Gets {
Get[] value();
}
//analog Post- und Posts-Annotationen
public class RouteScanner {
public static void scan(Router router, Class<?> controllerClass) {
for(Method method : controllerClass.getMethods()) {
for(Get get : method.getAnnotationsByType(Get.class)) {
router.GET().route(get.value()).with(controllerClass, method.getName());
}
for(Post post : method.getAnnotationsByType(Post.class)) {
router.POST().route(post.value()).with(controllerClass, method.getName());
}
}
}
}
public class UserController{
@Get("/login")
public Result login(Context context) {...}
...
}
public class Routes implements ApplicationRoutes {
@Override
public void init(Router router) {
RouteScanner.scan(router, ApplicationController.class);
RouteScanner.scan(router, UserController.class);
...
}
}
Das scheint gut zu funktionieren. Vor allem beschwöre ich keine großartige Magie - ich muss immer noch sagen, welche Controller gescannt werden sollen und kann auch Routen per Hand eintragen, wenn ich will. Aber es können bei den annotierten Methoden keine Tippfehler mehr passieren, und ich muss normalerweise nur noch zwei Stellen im Auge behalten (Template und Controller).
Oder übersehe ich was?