在PlayFramework 2.4中,我尝试将所有控制器方法转换为JavaScript路径。
val jsRoutesClass = classOf[routes.javascript]
val controllers = jsRoutesClass.getFields.map(_.get(null))
for (
controller <- controllers;
method <- controller.getClass.getDeclaredMethods
) yield method.invoke(controller).asInstanceOf[JavaScriptReverseRoute]
但发生以下错误:
Error injecting constructor, java.lang.ClassCastException: java.lang.String cannot be cast to play.api.routing.JavaScriptReverseRoute
at controllers.Application.<init>(Application.scala:21)
while locating controllers.Application
for parameter 1 at router.Routes.<init>(Routes.scala:35)
while locating router.Routes
while locating play.api.inject.RoutesProvider
while locating play.api.routing.Router
我添加了一些代码,但我认为这是不必要的代码。在此之后,不会发生异常。
for (
controller <- controllers;
method <- controller.getClass.getDeclaredMethods;
action <- method.invoke(controller).toString
) yield method.invoke(controller).asInstanceOf[JavaScriptReverseRoute]
为什么错误出现在第一个代码示例中而不出现在第二个代码示例中?
答案 0 :(得分:4)
让我们一步一步看看代码,看看每行产生的结果。 我将您的代码转换为完整的示例代码,但我希望我能够捕获代码的本质。
package controllers
import play.api._
import play.api.mvc._
class Sample extends Controller {
def hello(name: String) = Action {
implicit req =>
import routes.javascript._
val jsRoutesClass = classOf[routes.javascript]
val controllers = jsRoutesClass.getFields.map(_.get(null))
val met = for (
controller <- controllers;
method <- controller.getClass.getDeclaredMethods
) yield method
Ok(met.mkString(", "))
}
}
执行此请求时,您会看到类似
的内容public play.api.routing.JavaScriptReverseRoute controllers.javascript.ReverseSample.hello(), public java.lang.String controllers.javascript.ReverseSample._defaultPrefix()
您应该从路径中找到所有方法,但请注意,还有_defaultPrefix()
方法,返回类型为String。
这是您的第一个代码示例不起作用的原因。其中一种方法不会返回JavaScriptReverseRoute
,因此会抛出异常。
这仍然无法解释为什么您的第二个代码示例不起作用。所以让我们在Sample Controller中添加一些代码:
package controllers
import play.api._
import play.api.mvc._
class Sample extends Controller {
def hello(name: String) = Action {
implicit req =>
import routes.javascript._
val jsRoutesClass = classOf[routes.javascript]
val controllers = jsRoutesClass.getFields.map(_.get(null))
val met = for (
controller <- controllers;
method <- controller.getClass.getDeclaredMethods
) yield method.invoke(controller)
Ok(met.mkString(", "))
}
}
请注意,我们尚未转换方法调用的结果,并且请求产生类似于:
的内容JavaScriptReverseRoute(controllers.Sample.hello,
function(name) {
return _wA({method:"GET", url:"/" + (function(k,v) {return v})("name", encodeURIComponent(name))})
}
),
仔细观察,你会看到最后有一个流氓,
意味着我们临时val met
的值在位置0的JavaScriptReverseRoute和位置1以及空字符串。
因此,查看您的解决方法,操作action <- method.invoke(controller).toString
是一个带有javascript一次的字符串,另一次是一个空字符串。由于我们处于理解状态,因此String会自动转换为字符数组,如果此数组为空,则不会执行yield块。
您的解决方法的问题是,如果_.defaultPrefix()
产生一个字符串,它将再次抛出一个类强制转换异常。
更好的解决方案是过滤每个没有例外结果类型的方法,如下所示:
package controllers
import play.api._
import play.api.mvc._
class Sample extends Controller {
def hello(name: String) = Action {
implicit req =>
import routes.javascript._
val jsRoutesClass = 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]
Ok(met.mkString(", "))
}
}
这应该导致预期的行为。