如何从 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:
.
上方的示例中提供的任何代码
我正在尝试为 运行 一些 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:
.