如何从 ScriptEngineManager 检索 Kotlin jsr223 脚本引擎?

How do I retrieve Kotlin jsr223 script engine from ScriptEngineManager?

我正在尝试为 运行 一些 Kotlin 脚本编写一个界面 (GUI)。我从 Junit 测试开始,以确保我可以执行脚本。我什至无法加载科特林引擎。看起来我的依赖项 (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似乎通过Class.forName成功加载,但名称kotlin并未注册,可用引擎列表仅包含Nashorn .如何确保引擎已注册?

好像kotlin脚本引擎不在默认的classloader中,所以需要在实例化ScriptEngineManager的时候指定一个classloader:

ScriptEngineManager(clazz.getClassLoader()) getEngineByName(引擎名称)?.factory

更新

在Java8中,如果在路径META_INF/services[=中查看$JAVA_HOME/jre/lib/ext/nashorn.jar 35=] 有一个名为 javax.script.ScriptEngineFactory 的文件。内容是:

jdk.nashorn.api.scripting.NashornScriptEngineFactory

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

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

org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory

你应该可以开始了。此外,您不需要在评论 // so far so good, but here's the problem:.

上方的示例中提供的任何代码