在 SBT 构建期间无法在同一个 jar 中找到 class

Cannot find class in same jar during SBT build

我正在尝试构建一个类似 swagger2markup 的 sbt 插件,但在 sbt 中执行此插件时遇到问题:

org.apache.commons.configuration2.ex.ConfigurationRuntimeException: java.lang.ClassNotFoundException: org.apache.commons.configuration2.PropertiesConfiguration
    at org.apache.commons.configuration2.beanutils.BeanHelper.fetchBeanClass(BeanHelper.java:549)
..snip..
Caused by: java.lang.ClassNotFoundException: org.apache.commons.configuration2.PropertiesConfiguration
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at org.apache.commons.lang3.ClassUtils.getClass(ClassUtils.java:909)

因此,尝试从同一 jar 中的 class 查找 PropertiesConfiguration 失败。似乎 sbt 运行s 在 classloader 中的任务不包含依赖项。当我 运行 来自 sbt 控制台的任务时会发生这种情况。

commons-configuration2 正在使用 commons-lang3 加载 ConfigurationBuilder 的 class 文件。 commons-lang 正在尝试使用当前线程中的 ClassLoader 来执行加载,请参阅 ClassUtils, but it seems that sbt doesn't give you any guaranties about Thread.currentThread().getContextClassLoader, see discussion 了解更多详细信息。

解决方法是手动加载当前线程class,例如:

Thread.currentThread().setContextClassLoader(
  PluignObject.getClass.getClassLoader
)

但老实说,我不确定这个解决方案的安全性。

我最终采用的解决方法是在分叉的 jvm 进程中调用任务:

val runner: ScalaRun = initScoped(myTask.scopedKey, Defaults.runnerInit).value
val log: Logger = streams.value.log
val arguments = Seq()
runner.run(mainClass, classpath.map(_.data), arguments, log)

当我使用的工具中有一个主要 class 可用时,这对我有用。