1

我正在尝试编写一个界面(GUI)来运行一些 Kotlin 脚本。我从一个 Junit 测试开始,以确保我可以执行脚本。我什至无法加载 kotlin 引擎。看起来我的依赖项(gradle)是有序的,但你可以仔细检查一下。

compile name: 'kotlin-script-runtime',
    group: 'org.jetbrains.kotlin', version: kotlin_version
compile name: 'kotlin-script-util',
    group: 'org.jetbrains.kotlin', version: kotlin_version
compile name: 'kotlin-compiler-embeddable',
    group: 'org.jetbrains.kotlin', version: kotlin_version

多于:ext.kotlin_version = '1.3.0'

这是失败的测试:

@Test
fun testEngine() {
  // attempt to load script engine class before looking for it
  val ktsEngineClassName = "org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine";
  var clazz: Class<*>? = null;
  // assign the clazz variable inside a closure to catch ClassNotFound
  assertDoesNotThrow({clazz = Class.forName(ktsEngineClassName)}, "could not find $ktsEngineClassName")
  // just to make sure it's there
  assertNotNull(clazz, "could not find $ktsEngineClassName")

  // so far so good, but here's the problem:
  val engineName = "kotlin"
  // load the factory
  val factory = ScriptEngineManager().getEngineByName(engineName)?.factory
  // and test that we got it
  assertNotNull(factory, "didn't find factory for '$engineName'." +
      "\navailable: ${ScriptEngineManager().engineFactories}")
}

最后一次assertNotNull失败,输出如下:

org.opentest4j.AssertionFailedError: didn't find factory for 'kotlin'.
available: [jdk.nashorn.api.scripting.NashornScriptEngineFactory@1a41b1fc] ==> expected: not <null>

可以看到,虽然脚本引擎类似乎加载Class.forName成功,但名称kotlin并没有注册,可用引擎列表只包含 Nashorn。如何确保引擎已注册?

4

1 回答 1

2

看起来kotlin脚本引擎不在默认的类加载器中,所以在实例化ScriptEngineManager时需要指定一个类加载器:

ScriptEngineManager(clazz.getClassLoader()) getEngineByName(engineName)?.factory

更新

在 Java 8 中,如果您查看路径META_INF/services中的$JAVA_HOME/jre/lib/ext/nashorn.jar ,则会有一个名为javax.script.ScriptEngineFactory的文件。内容是:

jdk.nashorn.api.scripting.NashornScriptEngineFactory

因此,当ScriptEngineManager查找ScriptEngine实现时,它会扫描类路径以查找命名的条目/META-INF/services/javax.script.ScriptEngineFactory并从找到的每个条目中加载类名。

通常,包含您的目标脚本引擎的 jar 将包含其自己的服务文件,但是,如果您的 kotlin 脚本引擎已经在类路径中,我认为您可以创建一个/META-INF/services/javax.script.ScriptEngineFactory使用纯文本上下文调用的类路径资源

org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory

你应该很高兴。此外,您不需要您在评论上方的示例中提供的任何代码// so far so good, but here's the problem:

于 2018-10-31T13:11:28.830 回答