Less Verbose way of generating Play 2's javascript router

前端 未结 5 843
北海茫月
北海茫月 2021-02-06 00:54

Currently I define my app\'s javascript router in a fairly verbose way

def javascriptRoutes = Action { implicit request =>
  import routes.javascript._
  Ok(R         


        
相关标签:
5条回答
  • 2021-02-06 00:58

    You can do it via reflection like so:

    val routeCache = {
        import routes._
        val jsRoutesClass = classOf[routes.javascript]
        val controllers = jsRoutesClass.getFields().map(_.get(null))
        controllers.flatMap { controller =>
            controller.getClass().getDeclaredMethods().map { action =>
                action.invoke(controller).asInstanceOf[play.core.Router.JavascriptReverseRoute]
            }
        }
    }
    
    def javascriptRoutes = Action { implicit request =>
        Ok(Routes.javascriptRouter("jsRoutes")(routeCache:_*)).as("text/javascript")
    }
    

    This was derived from the generated source files found in target/scala-2.x.x/src_managed. You could actually add your own source generator and parse the routes file yourself, but I find doing it via reflection easier.

    An additional thing you might want to do is filter out the methods you don't want as this will give you ALL the routes (including the javascriptRouter itself).

    0 讨论(0)
  • 2021-02-06 01:07

    Also, if you are using Play 2.4, some Classes/packages have been changed:

    def javascriptRoutes = Action { implicit request =>
      Ok(play.api.routing.JavaScriptReverseRouter("jsRoutes")(routeCache:_*)).as("text/javascript")
    }
    
    val routeCache: Array[JavaScriptReverseRoute] = {
      import routes._
      val jsRoutesClass: Class[javascript] = classOf[routes.javascript]
      val controllers = jsRoutesClass.getFields.map(_.get(null))
      val met = for (
        controller <- controllers;
        method <- controller.getClass.getDeclaredMethods if method.getReturnType == classOf[play.api.routing.JavaScriptReverseRoute]
      ) yield method.invoke(controller).asInstanceOf[play.api.routing.JavaScriptReverseRoute]
      met
    }
    
    0 讨论(0)
  • 2021-02-06 01:13

    I needed that in java. Copying it here in case it is of use for someone.

    public static Result javascriptRoutes() throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
    
        // use reflection to get the fields of controllers.routes.javascript
        Set<Object> reverseRoutes = new HashSet<Object>();
        for (Field f : controllers.routes.javascript.class.getFields()) {
            // get its methods
            for (Method m : getAllMethods(f.getType(), withReturnType(JavascriptReverseRoute.class))) {
                // for each method, add its result to the reverseRoutes
                reverseRoutes.add(m.invoke(f.get(null)));
            }
        }
    
        // return the reverse routes
        response().setContentType("text/javascript");
        return ok(Routes.javascriptRouter("jsRoutes",
                reverseRoutes.toArray(new JavascriptReverseRoute[reverseRoutes.size()])));
    }
    
    0 讨论(0)
  • 2021-02-06 01:18

    Expanding @rochb's answer for Play 2.4 Java, where the package names are slightly different, with support for multiple controller packages.

    public Result javascriptRoutes() throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
    
        // use reflection to get the fields of controllers.routes.javascript and other controller packages
        Set<Object> reverseRoutes = new HashSet<Object>();
        Class[] routeClasses = {controllers.routes.javascript.class, com.example.package1.routes.javascript.class, com.example.package2.routes.javascript.class};
        for (int i = 0; i < routeClasses.length; i++) {
            for (Field f : routeClasses[i].getFields()) {
                // get its methods
                for (Method m : getAllMethods(f.getType(), withReturnType(play.api.routing.JavaScriptReverseRoute.class))) {
                    // for each method, add its result to the reverseRoutes
                    reverseRoutes.add(m.invoke(f.get(null)));
                }
            }
        }
        // return the reverse routes
        response().setContentType("text/javascript");
        return ok(Routes.javascriptRouter("jsRoutes",
                reverseRoutes.toArray(new play.api.routing.JavaScriptReverseRoute[reverseRoutes.size()])));
    }
    
    0 讨论(0)
  • 2021-02-06 01:21

    Very nice solution by thatsmydoing. If you have the JavaScript-routes under some other subpackage, you need to declare routeCache like this

    val routeCache = {
      val jsRoutesClass = classOf[controllers.api.routes.javascript]
      val controllerArray = jsRoutesClass.getFields().map(_.get(null))
      controllerArray.flatMap { controller =>
        controller.getClass().getDeclaredMethods().map { action =>
        action.invoke(controller).asInstanceOf[play.core.Router.JavascriptReverseRoute]
      }
     }
    }
    
    0 讨论(0)
提交回复
热议问题