我需要使用反射运行编译时任务(打扰调用者和被调用者是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)内容。
感谢线索,this.is.frustrating; - )
答案 0 :(得分: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)