动态类加载Scala类型

动态类加载Scala类型,scala,classloader,Scala,Classloader,我有以下Scala类层次结构: abstract class BaseModule(val appConf : AppConfig) { // ... } class SimpleModule(appConf : AppConfig) extends BaseModule(appConf) { // ... } class FairlyComplexModule(appConf : AppConfig) extends BaseModule(appConf) { // ... }

我有以下Scala类层次结构:

abstract class BaseModule(val appConf : AppConfig) {
  // ...
}

class SimpleModule(appConf : AppConfig) extends BaseModule(appConf) {
  // ...
}

class FairlyComplexModule(appConf : AppConfig) extends BaseModule(appConf) {
  // ...
}

// dozens of other BaseModule subclasses...
在运行时,我的应用程序将为要实例化的
BaseModule
子类的完全限定类名接受一个字符串输入参数,但代码不知道它将是哪个具体的子类。因此,我:

val moduleFQCN = loadFromInputArgs()  // ex: "com.example.myapp.SimpleModule"
val moduleClass = Class.forName(moduleFQCN)
println(s"Found ${moduleFQCN} on the runtime classpath.")
val module = Class.forName(moduleFQCN).getConstructor(classOf[AppConfig]).newInstance(appConf).asInstanceOf[BaseModule]
这样,输入指定在类路径上查找哪个
BaseModule
子类,然后实例化。上面的前三行执行得很好,我看到
println
fire。但是,上面的最后一行引发异常:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    <rest of stacktrace omitted for brevity>
线程“main”java.lang.reflect.InvocationTargetException中的异常 位于sun.reflect.NativeConstructorAccessorImpl.newInstance0(本机方法) 位于sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
很明显,当我试图创建
SimpleModule
子类的实例时,我做了一些错误的事情,只是不知道它是什么。有什么想法吗?

您可能失败了,因为您在没有任何参数的情况下调用了
newInstance()
,但是没有找到默认构造函数,因此实例化失败

试试这个:

Class.forName(moduleFQCN).getConstructor(classOf[AppConfig])
.newInstance(appConf).asInstanceOf[BaseModule]

其中
appConf
AppConfig
的实例,是实例化
BaseModule
的参数。

您可能会失败,因为您调用
newInstance()
时没有任何参数,但没有找到默认构造函数,因此实例化失败

试试这个:

Class.forName(moduleFQCN).getConstructor(classOf[AppConfig])
.newInstance(appConf).asInstanceOf[BaseModule]

其中
appConf
AppConfig
的一个实例,是实例化
BaseModule
的参数。

谢谢@Alon Segal(+1)我想您已经了解了默认构造函数的一些内容,但是您使用简单字符串的示例对我没有帮助。我认为另一个复杂的因素是代码知道需要一些
BaseModule
subclass,但在运行时才需要。如果您可以将您的示例更改为使用我的
BaseModule
用例,并且对我有效,我将很高兴地给您绿色支票!再次感谢!再次感谢(+1),我想我们离得越来越近了,但还不是很近。请查看我更新的问题/代码片段和正在生成的新异常(
InvocationTargetException
)。思想?再次非常感谢!我正试图重现您的错误,您能告诉我引发异常的“moduleFQCN”的值吗?这可能是因为异常是从您试图实例化的构造函数中引发的…感谢@Alon Segal(+1)我想您已经了解了默认构造函数的一些内容,但是,您使用简单字符串的示例对我没有帮助。我认为这里的另一个复杂因素是代码知道需要一些
BaseModule
子类,但直到运行时才知道。如果您可以将您的示例更改为使用我的
BaseModule
用例,并且对我有效,我将很高兴地给您绿色支票!再次感谢!再次感谢(+1),我想我们离得越来越近了,但还不是很近。请查看我更新的问题/代码片段和正在生成的新异常(
InvocationTargetException
)。思想?再次非常感谢!我正在试图重现您的错误,您能告诉我引发异常的“moduleFQCN”的值吗?这可能是因为异常是从您试图实例化的构造函数中引发的……作为引发异常的
InvocationTargetException
检查通过
getCause()引发的实际异常
首先。检查
appConfig
在调用时是否有效。您正在实例化的类的构造函数可能正在引发异常。从for
newInstance
@throws InvocationTargetException-如果基础构造函数引发异常
,则您给出的代码不是问题,相反,在对象创建过程中存在一个问题。为了取得更大的进步,您应该向我们提供所有令人不快的堆栈跟踪或更多的真实代码。+1至
rxg
的评论:阿隆的回答解决了您发布的问题;为了解决您的新问题,我们需要堆栈跟踪中的内部异常,您在堆栈跟踪中发布了“为简洁起见省略了stacktrace的其余部分”。使用
scala.reflect.internal.util.scalacsloader.create(fqcn,onError)
,您可能会得到更好的ergnonomics。使用
ScalaClassLoader.apply(classLoader)
。作为导致异常的
InvocationTargetException
a,首先检查通过
getCause()引发的实际异常。检查
appConfig
在调用时是否有效。您正在实例化的类的构造函数可能正在引发异常。从for
newInstance
@throws InvocationTargetException-如果基础构造函数引发异常
,则您给出的代码不是问题,相反,在对象创建过程中存在一个问题。为了取得更大的进步,您应该向我们提供所有令人不快的堆栈跟踪或更多的真实代码。+1至
rxg
的评论:阿隆的回答解决了您发布的问题;为了解决您的新问题,我们需要堆栈跟踪中的内部异常,您在堆栈跟踪中发布了“为简洁起见省略了stacktrace的其余部分”。使用
scala.reflect.internal.util.scalacsloader.create(fqcn,onError)
,您可能会得到更好的ergnonomics。使用ScalaClassLoader.apply(classLoader)
创建它。