在SBT中运行代码时出现ClassCastException

时间:2015-12-05 16:13:11

标签: scala sbt classloader

我的代码大致如下:

val classLoader = new URLClassLoader(entry.jars, Thread.currentThread.getContextClassLoader)
val env = classLoader.loadClass(entry.name).asSubclass(classOf[Environment])

对于上下文:"条目"是JAR文件和类名的集合。该课程预计将延长EnvironmentEnvironment在同一个包中定义,并且不使用任何类加载技巧。 JAR文件的集合仅包含指定类所需的类,仅此而已(仅限任何父级ClassLoader已加载的内容)。

当我使用run从sbt中运行这段代码时,一切正常。但是如果我在同一个sbt shell中第二次运行它,我会得到:

[error] (run-main-1) java.lang.ClassCastException: class edu.tum.cs.isabelle.impl.Environment
java.lang.ClassCastException: class edu.tum.cs.isabelle.impl.Environment
    at java.lang.Class.asSubclass(Class.java:3404)

我无法理解这里的问题:在运行之间没有重新编译或任何东西。我为test执行了类似的代码,它在那里工作正常。当我将fork设置为true时,它确实有效,但我没有理由这样做。

为了进行调试,我检查了getClassLoader classOf[Environment]以及加载类的超类。果然,在第一次运行中,它们是等效的,但不是在第二次运行中。不过,他们的toString表示是不确定的。

编辑:更多调试。我打印出所有相关类加载器的System.identityHashCode

println(s"self: " + System.identityHashCode(classOf[Environment].getClassLoader))
println(s"fresh: " + System.identityHashCode(classLoader))
println(s"impl: " + System.identityHashCode(classLoader.loadClass(entry.name).getClassLoader))
println(s"impl.parent: " + identityHashCode(classLoader.loadClass(entry.name).getSuperclass.getClassLoader))

首次运行的结果:

self: 1209891953
fresh: 1734438968
impl: 1734438968
impl.parent: 1209891953

第二轮的结果:

self: 1952422714
fresh: 1110295313
impl: 1110295313
impl.parent: 1209891953

1 个答案:

答案 0 :(得分:1)

Rob Norris在其他地方提出了解决方案。由于当前Thread的类加载器可以是"字面上任何",我应该确保使用用于加载Environment的类加载器。果然,如果我将代码更改为

val classLoader = new URLClassLoader(entry.jars, getClass.getClassLoader)

代码按预期工作。

相关问题