Scala - 动态对象/类加载 [英] Scala - Dynamic object/class loading

查看:179
本文介绍了Scala - 动态对象/类加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  ClassLoader classLoader = new URLClassLoader(在Java文件中) new URL [] {
new File(module.jar)。toURI()。toURL()});
Class clazz = classLoader.loadClass(my.class.name);
对象实例= clazz.newInstance();

//检查并转换到一个接口,然后使用它
if(instance instanceof MyInterface)
...

它的工作正常。



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



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

  trait模块{
def name:String
}

对象模块{
lazy val ModuleClassName =my.module.ExModule
}

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

  package my.module 

import模块

对象ExModule extends Module {}

然后我用这段代码加载:

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

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

  java.lang.InstantiationException:my.module.ExModule 

如果我测试:

 code> clazz.isInstanceOf [Module] 

- >总是返回



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



编辑



我猜是因为 ExModule 是一个 / code>(不是 class )。但是当我将它更改为 class ,而 classLoader.loadClass(...)提出了一个 java.lang.NoClassDefFoundError 。我想这是因为 ExModule trait 中扩展。



我很困惑任何人都可以帮助我吗?



已编辑

  clazz.isInstanceOf [Class [Module]] //或Class [Byte]或Class [_] ... 

返回 true

解决方案

糟糕。我得到了答案。



了解:





========= ============================================================================================================================================================================================ / trait ...从外部jar文件。还是因为我找不到正确的方法。但是目前这有助于我解决问题。

  var classLoader = new java.net.URLClassLoader(
Array新的File(module.jar)toURI.toURL),
/ *
*需要指定parent,所以我们在当前上下文中有所有的类实例
*
* /
this.getClass.getClassLoader

/ *
*请注意,后缀$用于Scala对象,
*这是一个技巧b $ b * /
var clazzExModule = classLoader.loadClass(Module.ModuleClassName +$)

/ *
*目前,我不知道如何检查clazzExModule是
* Class [Module]的实例,因为clazzExModule.isInstanceOf [Class [_]]总是
*返回true,
*所以我使用try / catch
* /
尝试{
//MODULE $是一个技巧,我不知道get(null)
var module = clazzExModule.getField(MODULE $)。 get(null).asInstanceOf [Module]
} catch {
case e:java.lang.ClassCastException =>
printf( - %s不是Module\\\
,clazzExModule)
}

这就是: - )



已编辑



更好的设计 ExModule 作为一个类。从jar文件加载后,我可以像下面这样查看:

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

注意:



你不能这样做:

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

因为模块是一个 trait / 对象 isAssignableFrom()在这种情况下不起作用。


In Java, I load external class (in .jar file) by this way:

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)
  ...

And it works fine.

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

Now I want to do the same thing in Scala. I have a trait named Module (Module.scala):

trait Module {
  def name: String
}

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

I write a module extending Module, then compile it to module.jar:

package my.module

import Module

object ExModule extends Module {}

Then I load it by this code:

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

It works fine. But if I create new instance, I get this exception:

java.lang.InstantiationException: my.module.ExModule

If I test it:

clazz.isInstanceOf[Module]

-> always return false.

So could you help me on this problem?

Edited

I guess it is because ExModule is an object (not class). But when I change it to class, and classLoader.loadClass(...) raises a java.lang.NoClassDefFoundError. I guess it is because ExModule is extended from a trait.

I'm confused. Could anyone please help me?

Edited

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

returns true.

解决方案

Oops... I got the answer.

Learn from:

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

I guess this way is temporary before Scala team provides right way to load an object/class/trait... from external jar file. Or because I can't find out the right way. But currently this helps me out of the problem.

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)
}

That's all :-)

Edited

I'd better design ExModule as a class. After loading it from jar file, I can check it as like as:

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

Note:

You can not do it the opposite way:

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

because Module is a trait/object, isAssignableFrom() will not work in this case.

这篇关于Scala - 动态对象/类加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆