Scala - 动态对象/类加载

19 load scala dynamic object

在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)
  ...
Run Code Online (Sandbox Code Playgroud)

它工作正常.

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

现在我想在Scala中做同样的事情.我有一个trait名字Module(Module.scala):

trait Module {
  def name: String
}

object Module {
  lazy val ModuleClassName = "my.module.ExModule"
}
Run Code Online (Sandbox Code Playgroud)

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

package my.module

import Module

object ExModule extends Module {}
Run Code Online (Sandbox Code Playgroud)

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

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

它工作正常.但是如果我创建新实例,我会得到以下异常:

java.lang.InstantiationException: my.module.ExModule
Run Code Online (Sandbox Code Playgroud)

如果我测试它:

clazz.isInstanceOf[Module]
Run Code Online (Sandbox Code Playgroud)

- >总是回来false.

你能帮我解决这个问题吗?

编辑

我想这是因为ExModuleobject(不class).但是,当我改变它class,并classLoader.loadClass(...)提出一个java.lang.NoClassDefFoundError.我想这是因为ExModule从a扩展trait.

我糊涂了.有人可以帮帮我吗?

编辑

clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...
Run Code Online (Sandbox Code Playgroud)

回报true.

小智 12

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

借鉴:

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

我想在Scala团队提供object/class/trait从外部jar文件加载...的正确方法之前,这种方式是暂时的.或者因为我找不到正确的方法.但目前这有助于我摆脱困境.

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)
}
Run Code Online (Sandbox Code Playgroud)

就这样 :-)

编辑

我最好设计ExModule成一个班级.从jar文件加载后,我可以检查它:

var clazz = classLoader.loadClass(Module.ModuleClassName)
if (classOf[Module].isAssignableFrom(clazz))
  ...
Run Code Online (Sandbox Code Playgroud)

注意:

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

if (clazz.isAssignableFrom(classOf[Module]))
Run Code Online (Sandbox Code Playgroud)

因为Moduletrait/ object,isAssignableFrom()在这种情况下不起作用.