【问题标题】:How do I retrieve Kotlin jsr223 script engine from ScriptEngineManager?如何从 ScriptEngineManager 检索 Kotlin jsr223 脚本引擎?
【发布时间】:2019-04-02 23:24:18
【问题描述】:

我正在尝试编写一个界面 (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。如何确保引擎已注册?

【问题讨论】:

    标签: kotlin scripting jsr223 jvm-languages javax.script


    【解决方案1】:

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

    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:

    【讨论】:

    • 似乎是一个很有希望的建议,但没有帮助(仍然只有 Nashorn 可从该 ScriptEngineManager 获得)。它对你有用吗?
    • 呃,没有。未启用 kotlin。但是第 3 方脚本 jar 也有同样的问题。但是,现在我考虑了一下,我认为您还需要在库 jar 中的 services 文件,因为脚本引擎使用服务定位器来查找实现。让我举个例子。
    • 如果这是真的,那将是 'kotlin-compiler-embeddable' 依赖项的错误。也许我会尝试解决它。​​
    • 我可以通过在我的代码仓库的资源目录中添加文本文件来做到这一点。 mkdir -pv src/main/resources/META-INF/services 然后echo org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory &gt; src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
    猜你喜欢
    • 2019-04-03
    • 2011-07-30
    • 2017-11-02
    • 2021-12-28
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 2023-01-25
    相关资源
    最近更新 更多