理解 asInstanceOf 时的 ClassCastException
ClassCastException when asInstanceOf in for comprehension
在 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]
为什么错误出现在第一个代码示例中而不是第二个?
让我们一步一步地看代码,看看每一行产生什么。
我将您的代码转换为完整的示例代码,但我希望我抓住了您代码的本质。
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()
方法 return 类型字符串。
这就是您的第一个代码示例不起作用的原因。其中一种方法没有 return JavaScriptReverseRoute
,因此抛出异常。
这仍然不能解释为什么您的第二个代码示例不起作用。因此,让我们向示例控制器添加一些代码:
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 a JavaScriptReverseRoute 和位置 1 和空字符串。
因此,查看您的解决方法,操作 action <- method.invoke(controller).toString
是一个带有 javascript 的字符串,另一次是空字符串。由于我们在理解中,字符串会自动转换为字符数组,如果该数组为空,则不会执行 yield 块。
您的解决方法的问题是,如果 _.defaultPrefix()
曾经产生一个字符串,它将再次抛出一个 class 转换异常。
更好的解决方案是过滤每个没有您的例外结果类型的方法,如下所示:
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(", "))
}
}
这应该会导致预期的行为。
在 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]
为什么错误出现在第一个代码示例中而不是第二个?
让我们一步一步地看代码,看看每一行产生什么。 我将您的代码转换为完整的示例代码,但我希望我抓住了您代码的本质。
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()
方法 return 类型字符串。
这就是您的第一个代码示例不起作用的原因。其中一种方法没有 return JavaScriptReverseRoute
,因此抛出异常。
这仍然不能解释为什么您的第二个代码示例不起作用。因此,让我们向示例控制器添加一些代码:
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 a JavaScriptReverseRoute 和位置 1 和空字符串。
因此,查看您的解决方法,操作 action <- method.invoke(controller).toString
是一个带有 javascript 的字符串,另一次是空字符串。由于我们在理解中,字符串会自动转换为字符数组,如果该数组为空,则不会执行 yield 块。
您的解决方法的问题是,如果 _.defaultPrefix()
曾经产生一个字符串,它将再次抛出一个 class 转换异常。
更好的解决方案是过滤每个没有您的例外结果类型的方法,如下所示:
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(", "))
}
}
这应该会导致预期的行为。