如何将JavaScript函数传递给Java方法以充当回调(Rhino)

基本上我正在尝试将javaScript函数传递给Java方法以充当脚本的回调。

我可以做到 – 有点 – 但我收到的对象是sun.org.mozilla.javascript.internal.InterpretedFunction,我没有看到调用它的方法。

有任何想法吗?

这是我到目前为止所拥有的:

var someNumber = 0; function start() { // log is just an log4j instance added to the Bindings log.info("started...."); someNumber = 20; // Test is a unit test object with this method on it (taking Object as a param). test.callFromRhino(junk); } function junk() { log.info("called back " + someNumber); } 

实现一个接口:

 import javax.script.*; public class CallBack { public void invoke(Runnable runnable) { runnable.run(); } public static void main(String[] args) throws ScriptException { ScriptEngine js = new ScriptEngineManager().getEngineByExtension("js"); js.getContext().setAttribute("callBack", new CallBack(), ScriptContext.ENGINE_SCOPE); js.eval("var impl = { run: function () { print('Hello, World!'); } };\n" + "var runnable = new java.lang.Runnable(impl);\n" + "callBack.invoke(runnable);\n"); } } 

sun.org.mozilla.javascript.internal.InterpretedFunction实现了sun.org.mozilla.javascript.Function接口。 该接口有一个名为call的方法,它接受:

  • 一个Context
  • 用作范围的Scriptable
  • 一个Scriptable ,用作函数中的this
  • 一个Objects数组,它是函数的参数

所以,我建议在java中你将你传递的对象转换为sun.org.mozilla.javascript.Function并调用call 。 前两个参数可以是您在java中首先启动脚本时使用的任何参数。 你在那里使用它的方式,最后两个参数可以是nullnew Object[0]

解决方案实际上是在另一个脚本中调用它。 这种作品:

 import javax.script.*; public class CallFunction { /** * @param args * @throws Exception oops! */ public static void main(String[] args) throws Exception { ScriptEngine js = new ScriptEngineManager().getEngineByExtension("js"); js.getContext().setAttribute("out", System.out, ScriptContext.ENGINE_SCOPE); Object a = js.eval( "out.println('Defining function a...');" + "function a() {out.println('hello from JavaScript!'); }" + "function foobar() {out.println('in foobar() definition');}" + "out.println('Done!.');" ); System.out.println(js.get("a")); // InterpretedFunction SimpleBindings bindings = new SimpleBindings(); bindings.put("foobar",js.get("a")); js.eval("foobar();", bindings); // hello from JavaScript js.eval("foobar();"); // in foobar() definition } } 

当您返回对函数的引用时,您需要让引擎为您执行该函数。 虽然不是很漂亮,但是通过一组特定的绑定向js eval()询问它实际上会为你完成这项工作。 您需要注意您操作的变量属于正确的范围; 我想在这里犯错很容易。

这个例子包括用javascript实现java接口。 这也可以用于从java调用javascript回调。

 package com.hal.research; import javax.script.*; public class CallFunction { /** * define contract for the callback */ static interface WhatEverYouWant { public String testMe(String a, String b); } /** * @param args */ public static void main(String[] args) throws Exception { final ScriptEngineManager scriptManager = new ScriptEngineManager(); final ScriptEngine js = scriptManager.getEngineByExtension("js"); js.put("producer", new Object() { /** * @param call is a callback to be invoked */ public void doSomethingWithIt(WhatEverYouWant call) { System.out.println("invoke callback javascript..."); String result = call.testMe("a", "b"); // do something with the result ... System.out.println("invoke callback...done, result: "+result); } }); js.eval( "var handler = {\"testMe\": function (a,b){return a + \" is concatenated to \"+ b;}};\n" + "var callback = new Packages.com.hal.research.CallFunction.WhatEverYouWant(handler);\n" + "producer.doSomethingWithIt(callback); "); } }
package com.hal.research; import javax.script.*; public class CallFunction { /** * define contract for the callback */ static interface WhatEverYouWant { public String testMe(String a, String b); } /** * @param args */ public static void main(String[] args) throws Exception { final ScriptEngineManager scriptManager = new ScriptEngineManager(); final ScriptEngine js = scriptManager.getEngineByExtension("js"); js.put("producer", new Object() { /** * @param call is a callback to be invoked */ public void doSomethingWithIt(WhatEverYouWant call) { System.out.println("invoke callback javascript..."); String result = call.testMe("a", "b"); // do something with the result ... System.out.println("invoke callback...done, result: "+result); } }); js.eval( "var handler = {\"testMe\": function (a,b){return a + \" is concatenated to \"+ b;}};\n" + "var callback = new Packages.com.hal.research.CallFunction.WhatEverYouWant(handler);\n" + "producer.doSomethingWithIt(callback); "); } }