在Java 7(1.7)中,我可以通过运行以下命令从JavaScript访问Java方法:
ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
jse.eval("importClass(net.apocalypselabs.symat.Functions);");
jse.eval("SyMAT_Functions = new net.apocalypselabs.symat.Functions();");
String input = "notify(\"Foo\");"; // This is user input
jse.eval("with(SyMAT_Functions){ "+input+" }");
哪个将从Functions java类运行notify()函数:
public class Functions {
private Object someObjectThatCannotBeStatic;
public void notify(Object message) {
JOptionPane.showMessageDialog(null, message.toString());
}
/* Lots more functions in here, several working with the same non-static variable */
}
如何使用Nashorn引擎访问Java 1.8中的Functions类?如果用户使用Java 1.8,我的目标是为第一个代码段运行不同的代码,同时仍允许1.7的用户使用该应用程序 .
我没试过http://www.doublecloud.org/2014/04/java-8-new-features-nashorn-javascript-engine/,https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.html和How to instantiate a Java class in JavaScript using Nashorn? . 他们似乎都没有像Java 1.7那样允许我,而是假设我只想访问静态函数和对象 .
我得到的最常见的错误:
我从...开始
ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
jse.eval("var SyMAT_Functions;with (new JavaImporter(Packages.net.apocalypselabs.symat)) {"
+ "SyMAT_Functions = new Functions();}");
...然后...
jse.eval("with(SyMAT_Functions){ "+input+" }");
...吐出......
TypeError: Cannot apply "with" to non script object in <eval> at line number 1
2 回答
我能够重现 . 首先,Nashorn一般不会尝试使用Java对象(非静态或其他方式) . 我已经在其他项目中使用它,并且没有任何重大问题从Java 7中的Rhino转换到migration guide中涵盖的内容 . 然而,根据MDN,这里的问题似乎是处理with statement的使用,这是"not recommended",甚至在ECMAScript 5.1的
strict
模式中也是不允许的 .与此同时,我发现a thread on the Nashorn-dev mailing list讨论了一个类似的案例 . 答复的相关部分是:
这不是最优雅的解决方案,但是,在不使用JDK 9的情况下,通过在Javascript中编写代理对象来镜像Java类的
public
API,我能够实现with
的预期用途:Attila Szegedi指出了非标准的Nashorn Object.bindProperties函数 . 虽然不能期望除了Nashorn引擎之外的任何东西,但它确实消除了重新声明
proxy
对象内所有公共API的复杂性 . 使用这种方法,第一个jse.eval(...)
调用可以替换为:我决定使用我的应用程序编译并捆绑“旧”Rhino解释器,而不是使用Nashorn .
https://wiki.openjdk.java.net/display/Nashorn/Using+Rhino+JSR-223+engine+with+JDK8