Подтвердить что ты не робот

Scala - Загрузка динамического объекта/класса

В 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 с именем Module (Module.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.

Так вы могли бы помочь мне в решении этой проблемы?

Edited

Я думаю, это потому, что ExModule является object (не class). Но когда я меняю его на class, а classLoader.loadClass(...) вызывает a java.lang.NoClassDefFoundError. Я думаю, это потому, что ExModule расширяется от a trait.

Я в замешательстве. Может ли кто-нибудь помочь мне?

Edited

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

возвращает true.

4b9b3361

Ответ 1

К сожалению... Я получил ответ.

Учитесь у:

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

Я предполагаю, что этот способ является временным до того, как команда 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 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)
}

Что все: -)

Edited

Мне лучше создать ExModule как класс. После загрузки из файла jar я могу проверить его как:

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

Примечание:

Вы не можете сделать это обратным образом:

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

потому что Module является trait/object, isAssignableFrom() в этом случае работать не будет.