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
を返します。
それで、この問題について私を助けてくれませんか?
編集済み
ExModule
はobject
(class
ではない)だからだと思います。しかし、それをclass
に変更すると、classLoader.loadClass(...)
は_Java.lang.NoClassDefFoundError
_を発生させます。 ExModule
がtrait
から拡張されているためだと思います。
よくわかりません。誰か助けてくれませんか?
編集済み
_clazz.isInstanceOf[Class[Module]]//or Class[Byte], or Class[_]...
_
true
を返します。
おっと...答えがわかりました。
から学びます:
https://stackoverflow.com/a/8868537/942821 (ニールにもう一度感謝します)。
====================
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]))
_
Module
はtrait
/object
であるため、この場合、isAssignableFrom()
は機能しません。