我遇到了 Nashorn 的一个问题,当评估一个大表达式时,它在 Java 8 中工作正常,但抛出一个java.lang.StackOverflowError
在Java 11中。
Exception in thread "main" java.lang.StackOverflowError
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterBinaryNode(LocalVariableTypesCalculator.java:444)
at org.openjdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:329)
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterJoinPredecessorExpression(LocalVariableTypesCalculator.java:777)
at org.openjdk.nashorn.internal.ir.JoinPredecessorExpression.accept(JoinPredecessorExpression.java:114)
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.visitExpression(LocalVariableTypesCalculator.java:603)
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterBinaryNode(LocalVariableTypesCalculator.java:447)
at org.openjdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:329)
我碰到这个问题 https://stackoverflow.com/questions/69812339/js-script-doesnt-run-with-java-11-but-works-with-java-8,并尝试解决此问题,如建议的那样这条评论 https://stackoverflow.com/a/69825990/7518719,我尝试将独立 Nashorn 与 Java 11 一起使用,方法是使用org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory
在我的代码中(参见这一页 https://github.com/szegedi/nashorn/wiki/Using-Nashorn-with-different-Java-versions#using-nashorn-on-java-11-to-14有关“为什么我们需要这样做”的信息)。
我有一个简单的 Maven 项目,我已将以下内容添加到我的 pom.xml 中:为简单起见,我仅包含以下重要部分:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>maven-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.openjdk.nashorn</groupId>
<artifactId>nashorn-core</artifactId>
<version>15.3</version>
</dependency>
</dependencies>
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
(除了这些,我正在使用maven-dependency-plugin
and maven-jar-plugin
将其捆绑到可执行 Jar 中)。
以下是我的Java代码:
主程序.java
package main;
import org.openjdk.nashorn.api.scripting.NashornScriptEngine;
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
import javax.script.ScriptEngine;
public class Main {
public static void main(String[] args) {
// write your code here
String expression = "(\"BUY\" == \"BUY\") && (\"BUY\" == \"BUY\") && (1.00 >= 1000.000)"; // It's a long expression which contains conditions like this.
try {
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
System.out.println("================================================================================");
System.out.println("factory.engineName: " + factory.getEngineName());
System.out.println("factory.engineVersion: " + factory.getEngineVersion());
System.out.println("factory.languageName: " + factory.getLanguageName());
System.out.println("factory.languageVersion: " + factory.getLanguageVersion());
System.out.println("================================================================================");
ScriptEngine engine = factory.getScriptEngine();
Object results = engine.eval(expression);
System.out.println("Successful");
System.out.println(results);
} catch (Exception e) {
e.printStackTrace();
}
}
}
带有Java版本java 版本“11.0.9”2020-10-20 LTS,我正在编译一个名为maven-project-1.0-SNAPSHOT.jar
通过做mvn clean install
.
运行Jar的主类时如下:
java -jar target/maven-project-1.0-SNAPSHOT.jar
基于此信息 https://github.com/szegedi/nashorn/wiki/Using-Nashorn-with-different-Java-versions#using-nashorn-on-java-11-to-14,独立版本的 Nashorn 将加载 Java 11,因为我已经使用了org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory
,因此,我不期望java.lang.StackOverflowError
使用 Java 11。
但我的输出产生了 StackOverflowError:
================================================================================
factory.engineName: OpenJDK Nashorn
factory.engineVersion: 15.3
factory.languageName: ECMAScript
factory.languageVersion: ECMA - 262 Edition 5.1
================================================================================
Exception in thread "main" java.lang.StackOverflowError
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterJoinPredecessorExpression(LocalVariableTypesCalculator.java:775)
at org.openjdk.nashorn.internal.ir.JoinPredecessorExpression.accept(JoinPredecessorExpression.java:114)
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.visitExpression(LocalVariableTypesCalculator.java:603)
at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterBinaryNode(LocalVariableTypesCalculator.java:447)
at org.openjdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:329)
Update:当编译这个时Java 17和测试,我没有收到 StackOverflowError。正如@Thorbjørn Ravn Andersen 所指出的
在评论中,检查这一点的原因是为了排除在 Java 11 中选择内置 Nashorn 而不是独立 Nashorn 的可能性。 (自从Java 17没有内置的 Nashorn,它只会选择独立的 Nashorn)。
基于此,我还可以想到对这个问题的补充:
我们如何确保独立的 Nashorn 被选中Java 11?
我尝试按如下方式执行jar(参考这个答案 https://stackoverflow.com/a/65267832/7518719 of 这个相关问题 https://stackoverflow.com/questions/65267831/intellij-put-some-dependencies-on-the-module-path-in-non-modular-application),但仍然抛出 StackOverflowError。 (这/path/to/my/maven-project/target/libs/
目录包含诸如nashorn-core-15.3.jar
, asm-7.3.1.jar
, asm-commons-7.3.1.jar
...)
java --module-path "/path/to/my/maven-project/target/libs/" --add-modules org.openjdk.nashorn -jar target/maven-project-1.0-SNAPSHOT.jar
(不是像这样传递参数/标志,更好的方法是将它们添加为诗歌中的配置等 - 并“更整洁”地处理它)。
仅供参考,以下代码可以很好地使用Java 8,但抛出相同的 StackOverflowErrorJava 11,这就是为什么我必须使用org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory
代替javax.script.ScriptEngineManager
.
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class Main {
public ScriptEngine engine = new ScriptEngineManager().getEngineByName(ENGINE_NAME);;
public static final String ENGINE_NAME = "nashorn";
public static void main(String[] args) {
// write your code here
Main main = new Main();
Object result = null;
String exp = "(1640 >= 10) && (1640 <= 100) && (1640 >= 123)";
try {
result = main.engine.eval(exp);
System.out.println(result);
} catch (ScriptException e) {
e.printStackTrace();
}
}
}
我在这里错过了什么吗?预先感谢您提供任何解决方案。