Scala - 动态对象/类加载

时间:2012-01-15 05:35:14

标签: scala object dynamic load

在Java中,我通过这种方式加载外部类(在.jar文件中):

ClassLoader classLoader = new URLClassLoader(new URL[] {
  new File("module.jar").toURI().toURL()});
Class clazz = classLoader.loadClass("my.class.name");
Object instance = clazz.newInstance();

//check and cast to an interface, then use it
if (instance instanceof MyInterface)
  ...

它运作正常。

====================

现在我想在Scala中做同样的事情。我有trait名为ModuleModule.scala):

trait Module {
  def name: String
}

object Module {
  lazy val ModuleClassName = "my.module.ExModule"
}

我编写了一个扩展Module的模块,然后将其编译为module.jar

package my.module

import Module

object ExModule extends Module {}

然后我用这段代码加载它:

var classLoader = new URLClassLoader(Array[URL](
  new File("module.jar").toURI.toURL))
var clazz = classLoader.loadClass(Module.ModuleClassName)

工作正常。但是如果我创建新实例,我会得到这个例外:

java.lang.InstantiationException: my.module.ExModule

如果我测试它:

clazz.isInstanceOf[Module]

- >始终返回false

那你可以帮我解决这个问题吗?

被修改

我想这是因为ExModuleobject(不是class)。但是当我将其更改为class时,classLoader.loadClass(...)会引发java.lang.NoClassDefFoundError。我想这是因为ExModule是从trait扩展而来的。

我很困惑。有人可以帮帮我吗?

被修改

clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...

返回true

2 个答案:

答案 0 :(得分:9)

哎呀......我得到了答案。

学习:

====================

我猜这种方式是临时的,因为Scala团队提供了从外部jar文件加载object/class/trait ...的正确方法。或者因为我找不到正确的方法。但目前这有助于我解决问题。

var classLoader = new java.net.URLClassLoader(
  Array(new File("module.jar").toURI.toURL),
  /*
   * need to specify parent, so we have all class instances
   * in current context
   */
  this.getClass.getClassLoader)

/*
 * please note that the suffix "$" is for Scala "object",
 * it's a trick
 */
var clazzExModule = classLoader.loadClass(Module.ModuleClassName + "$")

/*
 * currently, I don't know how to check if clazzExModule is instance of
 * Class[Module], because clazzExModule.isInstanceOf[Class[_]] always
 * returns true,
 * so I use try/catch
 */
try {
  //"MODULE$" is a trick, and I'm not sure about "get(null)"
  var module = clazzExModule.getField("MODULE$").get(null).asInstanceOf[Module]
} catch {
  case e: java.lang.ClassCastException =>
    printf(" - %s is not Module\n", clazzExModule)
}

这就是全部: - )

<强>被修改

我最好将ExModule设计成一个班级。从jar文件加载后,我可以像下面这样检查:

var clazz = classLoader.loadClass(Module.ModuleClassName)
if (classOf[Module].isAssignableFrom(clazz))
  ...

注意:

你不能以相反的方式做到这一点:

if (clazz.isAssignableFrom(classOf[Module]))

因为Moduletrait / objectisAssignableFrom()在这种情况下不起作用。

答案 1 :(得分:0)