Как я могу передать функцию 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); ");
    }
}