2

有一个编译时任务,我需要使用反射运行(调用者和被调用者是 Scala 源文件),但出现运行时错误:

java.lang.ClassCastException: 
scala.collection.immutable.Map$Map2 cannot be cast 
to scala.collection.immutable.Map

反射类:

object jsRoutes {
  def getRoutesMap: Map[String,String] = {...}
}

调用代码:(loader是 Scala 2.10.2 类加载器)

val appLoader = new java.net.URLClassLoader(path, loader)
val clazz = appLoader.loadClass("controllers.jsRoutes")
val routesMap = clazz.getMethod("getRoutesMap")

任何将 java.lang.Object 转换为预期返回类型的尝试都会Map[String,String]导致上述结果ClassCastException

routesMap.invoke(new Object).asInstanceOf[Map[String,String]]...

或不匹配:

routesMap.invoke(new Object) match {
  case x: Map[String,String] => ...
  case _ => println("not matched")
}

从未听说过 Map$Map2,在目标类中它是 Map[String,String] 所以不确定是什么在反射调用时转换返回类型。

可以打印未转换的 java.lang.Object (Map) 内容就好了。

感谢您提供线索,这.is.frustrating ;-)

4

1 回答 1

4

您可能正在尝试跨类加载器进行强制转换。你不能这样做——每个类加载器都维护自己的层次结构(对于那些没有传递给公共父加载器的类)。尝试调用getClassLoader您返回的地图和新创建的地图。

顺便说一句,Map$Map2这只是一个实现细节——Map用于处理二元素映射的子类。它正常投射就好了:

scala> val m = Map(1->"one", 2 -> "two"): Object
m: Object = Map(1 -> one, 2 -> two)

scala> m.getClass
res0: Class[_ <: Object] = class scala.collection.immutable.Map$Map2

scala> m.asInstanceOf[scala.collection.immutable.Map[Int,String]]
res1: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two)
于 2013-06-16T15:07:45.720 回答