Как я могу передать функцию javaScript методу Java, чтобы действовать как обратный вызов (Rhino)
в основном я пытаюсь передать функцию javaScript методу Java, чтобы действовать как обратный вызов скрипту.
Я могу это сделать-вроде - но объект, который я получаю, - это солнце.орг.mozilla.javascript.внутренний.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);
}
4 ответов
реализовать интерфейс:
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
что требуется:
- a
Context
- a
Scriptable
использовать в качестве рамки - a
Scriptable
использовать в качестве значенияthis
функции - массив
Objects
это аргументы для функции
Итак, я предлагаю, чтобы в java вы бросили объект, который был передан как sun.org.mozilla.javascript.Function
и звонок call
. Первые два аргумента могут быть тем, что вы использовали из java для запуска скрипта в первую очередь. Как вы используете его там, последние два аргумента могут быть null
и new 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 () для вас с определенным набором Привязок на самом деле сделает эту работу за вас. Вам нужно позаботиться о том, чтобы переменные, которыми вы манипулируете, принадлежали к правильной области; я думаю, здесь легко ошибаться.
этот пример охватывает реализацию интерфейса java с javascript. Это также может использоваться для вызова обратных вызовов javascript из java.
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); ");
}
}