在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+" }");
哪个将运行函数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
答案 0 :(得分:2)
我能够重现。首先,Nashorn一般不会尝试使用Java对象(非静态或其他方式)。我已经在其他项目中使用过它,并且没有任何重大问题从Java 7中的Rhino转换到migration guide所涵盖的内容。但是,这里的问题似乎与with
statement的使用有关,而{&#34;不推荐&#34;根据MDN,在ECMAScript 5.1的strict
模式下甚至不允许使用。
与此同时,我发现a thread on the Nashorn-dev mailing list正在讨论类似案例。答复的相关部分是:
Nashorn只允许脚本对象(即JS创建的对象) 构造函数或JS对象文字表达式)作为范围表达式 &#34;与&#34;声明。任意对象。 。 。不能用作&#39;范围&#39;的表达 &#39;与&#39;
在jdk9中,添加了支持镜像其他镜像对象 脚本引擎或其他全局变量(它们是ScriptObjectMirror的实例)。
它不是最优雅的解决方案,但是,如果不使用JDK 9,我可以通过在Javascript中编写代理对象来实现with
的预期用途。 >镜像Java类的public
API:
package com.example;
import javax.script.*;
public class StackOverflow27120811
{
public static void main(String... args) throws Exception {
ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
jse.eval(
"var real = new Packages.com.example.StackOverflow27120811(); " +
"var proxy = { doSomething: function(str) { return real.doSomething(str); } }; "
);
jse.eval("with (proxy) { doSomething(\"hello, world\"); } ");
}
public void doSomething(String foo) {
System.out.println(foo);
}
}
Attila Szegedi指出非标准 Nashorn Object.bindProperties函数。虽然它不能用于除Nashorn引擎之外的任何东西,但确实消除了重新声明proxy
对象内所有公共API的复杂性。使用此方法,第一个jse.eval(...)
调用可以替换为:
jse.eval(
"var real = new Packages.com.example.StackOverflow27120811(); " +
"var proxy = { }; " +
"Object.bindProperties(proxy, real); " // Nashorn-only feature
);
答案 1 :(得分:0)
我决定使用我的应用程序编译并捆绑“旧”Rhino解释器,而不是使用Nashorn。
https://wiki.openjdk.java.net/display/Nashorn/Using+Rhino+JSR-223+engine+with+JDK8