如何在Java15及更高版本中使用Nashorn?

我有一个现有的非模块化 Spring Boot 应用程序,它使用 Nashorn。该应用程序在 Java 14 上运行良好。

添加可用于 Java 15 的新 Nashorn 的 Maven 坐标后,应用程序在启动脚本引擎时失败。

public static void main(String[] args) throws ScriptException {
    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName("nashorn"); 
    engine.eval("print('Hello, World!');");
} 

错误信息:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "javax.script.ScriptEngine.eval(String)" because "engine" is null
    at xxxxx.yyyy.service.JavaScriptServiceImpl.main(JavaScriptServiceImpl.java:52)

是否需要将整个项目模块化才能使用 Nashorn?

回答

根据JEP 372,Nashorn 已从 JDK 15 中删除,但您可以从https://search.maven.org/artifact/org.openjdk.nashorn/nashorn-core/15.0/jar获取最新的 nashorn

对于 Maven,将以下依赖项包含到您的 pom.xml

<dependency>
  <groupId>org.openjdk.nashorn</groupId>
  <artifactId>nashorn-core</artifactId>
  <version>15.0</version>
</dependency>

对于 Gradle,将下面的依赖项包含到您的 build.gradle

implementation 'org.openjdk.nashorn:nashorn-core:15.0'

不幸的是,独立 Nashorn只能用作 JPMS 模块。因此,您可能需要遵循/sf/answers/3240248021/ 中所述的解决方案,使其适用于非模块化应用程序。

从给定的类xxxxx.yyyy.service.JavaScriptServiceImpl和基于@JornVernee 和@AttilaSzegedi 的反馈,命令行应该看起来像

jdk-15.0.1/bin/java -classpath /home/nashorn-helloworld/target/classes --module-path /home/org/openjdk/nashorn/nashorn-core/15.0:/home/org/ow2/asm/asm/7.3.1:/home/org/ow2/asm/asm-analysis/7.3.1:/home/org/ow2/asm/asm-commons/7.3.1:/home/org/ow2/asm/asm-tree/7.3.1/home/org/ow2/asm/asm-util/7.3.1 --add-modules org.openjdk.nashorn xxxxx.yyyy.service.JavaScriptServiceImpl

  • @AswathMurugan You only need `--add-modules org.openjdk.nashorn` but you're passing the `--module-path` argument as program argument, not as VM option, the `HelloWorld`, which I assume is your main class, goes all the way at the end of the command.
  • Furthermore, `--module-path` is a list of directories; you just need to list the directories where the modular JAR files are, not the JAR files themselves.

回答

Nashorn 维护者在这里。

Spring Boot 没有将 Nashorn 作为 JPMS 模块加载确实似乎是一个问题。Nashorn 将自己导出为一个脚本引擎,可以javax.script.ScriptEngineManager通过其module-info.java. 它不使用旧的、非模块化的导出机制,即通过META-INF/services/…其 JAR 文件中的相关条目来声明自己。这意味着如果 JAR 没有作为 JPMS 模块加载,脚本引擎管理器将不会发现它。(注意:即使它有多余的META-INF/services条目,也无济于事,因为 Nashorn 依赖于作为模块加载;作为曾经与 JDK 一起提供的代码,它自 Java 9 以来一直是一个模块……这会有点困难现在撤消。)

我创建了一个小型测试应用程序来确认情况确实如此。我正在尝试招募一些从事 Boot 工作的人来帮助我深入了解这件事。Boot 创建了一个胖 JAR 文件并将其所有依赖项打包到其中,然后管理它们的加载,因此这很复杂,因此您不能在启动时“仅”自己修改模块路径。

希望有一种方法可以告诉 Boot 将依赖项作为模块加载;到目前为止,我通过 Google 找到它的尝试并未取得成效。


回答

我刚刚发布了Nashorn 15.1,这使得 Nashorn 在通过类路径而不是通过模块路径加载时能够正常工作。我用我自己的一个小型 Spring Boot 应用程序对其进行了测试,并且可以正常工作。


以上是如何在Java15及更高版本中使用Nashorn?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>