Nashorn:如何在 Java 脚本执行之前在 Java 中预先设置 Java.type()-vars?
Nashorn: How to pre-set Java.type()-vars inside of Java before JavaScript execution?
我目前正在使用此 java 代码执行我的 JavaScript 脚本:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("awesome_script.js"));
我需要从 Java 脚本调用 Java 函数,所以我在 awesome_script.js
文件的顶部定义了它:
var first = Java.type('io.github.awesomeprogram.FirstClass');
var second = Java.type('io.github.awesomeprogram.SecondClass');
var extra = Java.type('io.github.awesomeprogram.ExtraClass');
然后我可以从这些 类 中调用一些方法,例如:
second.coolmethod("arg1",2);
我现在的问题是我需要在我的脚本中使用很多 java 类。我也有很多脚本,我认为在每个脚本中定义每一个 类 是非常低效的。
所以我正在寻找一种解决方案来创建在 JavaScript 内部创建的对象,在 Java 内部使用 Java.type()
,然后将它们传递给我要执行的脚本。
我该怎么做?
提前致谢!
经过大量研究,我找到了一种在执行前将全局变量放入 ScriptEngine 的方法:The Java Scripting API (Oracle Docs)
这使我能够将我想要的任何对象放入全局变量中。但是,我仍然需要一种方法来获取 Java.type()
在 Java 中创建的对象。所以我写了一个测试脚本,其中 returns 个对象,我发现它是 jdk.internal.dynalink.beans.StaticClass
类型的对象。这个 class 有一个构造函数,它接受一个普通的 Class
作为参数。遗憾的是,此构造函数在我的代码中不可用,因为它不可见。为了绕过这个,我使用了反射并制作了这个方法:
public StaticClass toNashornClass(Class<?> c) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class<?> cl = Class.forName("jdk.internal.dynalink.beans.StaticClass");
Constructor<?> constructor = cl.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
StaticClass o = (StaticClass) constructor.newInstance(c);
return o;
}
如果我将我想要的对象的 Class
作为全局变量传递,我只需要调用 toNashornClass(Example.class);
并将结果对象放入具有 engine.put("example",object);
[= 的全局变量中20=]
它工作正常。我可以完全像 Java.type()
.
创建的 var 一样使用 example
var
您可能希望避免在 "jdk.internal."、"jdk.nashorn.internal." 等软件包中使用 "internal" 类。在 jdk9 中,dynalink 是一个 API("jdk.dynalink" 有导出包)。在 jdk9 中,您可以调用 jdk.dyanlink.beans.StaticClass.forClass(Class) [ http://download.java.net/java/jdk9/docs/jdk/api/dynalink/jdk/dynalink/beans/StaticClass.html#forClass-java.lang.Class- ] 来构造 "type" 对象并将它们作为全局变量公开给脚本引擎。对于 jdk8,您可以在评估 "user" 脚本之前预先评估使用 Java.type(String) 调用的脚本。您还可以从 Java 代码调用 "Java.type" 函数。
jdk9的解决方案:
import jdk.dynalink.beans.StaticClass;
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
e.put("AList", StaticClass.forClass(java.util.ArrayList.class));
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
jdk8的解决方案:
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// eval a "boot script" before evaluating user script
// Note that this script could come from your app resource URL
e.eval("var AList = Java.type('java.util.ArrayList')");
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
jdk8的替代方案:
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// get Java.type function as object
JSObject javaTypeFunc = (JSObject) e.eval("Java.type");
// you can javaTypeFunc from java code many times
Object alType = javaTypeFunc.call(null, "java.util.ArrayList");
// expose that as global
e.put("AList", alType);
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
我目前正在使用此 java 代码执行我的 JavaScript 脚本:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("awesome_script.js"));
我需要从 Java 脚本调用 Java 函数,所以我在 awesome_script.js
文件的顶部定义了它:
var first = Java.type('io.github.awesomeprogram.FirstClass');
var second = Java.type('io.github.awesomeprogram.SecondClass');
var extra = Java.type('io.github.awesomeprogram.ExtraClass');
然后我可以从这些 类 中调用一些方法,例如:
second.coolmethod("arg1",2);
我现在的问题是我需要在我的脚本中使用很多 java 类。我也有很多脚本,我认为在每个脚本中定义每一个 类 是非常低效的。
所以我正在寻找一种解决方案来创建在 JavaScript 内部创建的对象,在 Java 内部使用 Java.type()
,然后将它们传递给我要执行的脚本。
我该怎么做?
提前致谢!
经过大量研究,我找到了一种在执行前将全局变量放入 ScriptEngine 的方法:The Java Scripting API (Oracle Docs)
这使我能够将我想要的任何对象放入全局变量中。但是,我仍然需要一种方法来获取 Java.type()
在 Java 中创建的对象。所以我写了一个测试脚本,其中 returns 个对象,我发现它是 jdk.internal.dynalink.beans.StaticClass
类型的对象。这个 class 有一个构造函数,它接受一个普通的 Class
作为参数。遗憾的是,此构造函数在我的代码中不可用,因为它不可见。为了绕过这个,我使用了反射并制作了这个方法:
public StaticClass toNashornClass(Class<?> c) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class<?> cl = Class.forName("jdk.internal.dynalink.beans.StaticClass");
Constructor<?> constructor = cl.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
StaticClass o = (StaticClass) constructor.newInstance(c);
return o;
}
如果我将我想要的对象的 Class
作为全局变量传递,我只需要调用 toNashornClass(Example.class);
并将结果对象放入具有 engine.put("example",object);
[= 的全局变量中20=]
它工作正常。我可以完全像 Java.type()
.
example
var
您可能希望避免在 "jdk.internal."、"jdk.nashorn.internal." 等软件包中使用 "internal" 类。在 jdk9 中,dynalink 是一个 API("jdk.dynalink" 有导出包)。在 jdk9 中,您可以调用 jdk.dyanlink.beans.StaticClass.forClass(Class) [ http://download.java.net/java/jdk9/docs/jdk/api/dynalink/jdk/dynalink/beans/StaticClass.html#forClass-java.lang.Class- ] 来构造 "type" 对象并将它们作为全局变量公开给脚本引擎。对于 jdk8,您可以在评估 "user" 脚本之前预先评估使用 Java.type(String) 调用的脚本。您还可以从 Java 代码调用 "Java.type" 函数。
jdk9的解决方案:
import jdk.dynalink.beans.StaticClass;
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
e.put("AList", StaticClass.forClass(java.util.ArrayList.class));
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
jdk8的解决方案:
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// eval a "boot script" before evaluating user script
// Note that this script could come from your app resource URL
e.eval("var AList = Java.type('java.util.ArrayList')");
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
jdk8的替代方案:
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// get Java.type function as object
JSObject javaTypeFunc = (JSObject) e.eval("Java.type");
// you can javaTypeFunc from java code many times
Object alType = javaTypeFunc.call(null, "java.util.ArrayList");
// expose that as global
e.put("AList", alType);
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}