web-dev-qa-db-ja.com

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.scala_)という名前のModuleがあります:

_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を返します。

それで、この問題について私を助けてくれませんか?

編集済み

ExModuleobjectclassではない)だからだと思います。しかし、それをclassに変更すると、classLoader.loadClass(...)は_Java.lang.NoClassDefFoundError_を発生させます。 ExModuletraitから拡張されているためだと思います。

よくわかりません。誰か助けてくれませんか?

編集済み

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

trueを返します。

20
user942821

おっと...答えがわかりました。

から学びます:

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

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/objectであるため、この場合、isAssignableFrom()は機能しません。

11
user942821
0
Chris Shain