2010-05-15 12 views
9

Zasadniczo próbuję przekazać funkcję javaScript do metody Java, aby zadzwonić do skryptu.Jak mogę przekazać funkcję javaScript do metody Java, aby działać jako wywołanie zwrotne (Rhino)?

Mogę to zrobić - w pewnym sensie - ale obiekt, który otrzymuję, to sun.org.mozilla.javascript.internal.InterpretedFunction i nie widzę sposobu, aby go wywołać.

Wszelkie pomysły?

Oto co mam do tej pory:

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); 
} 
+0

Czy to jest aplet? Jeśli nie, to niemożliwe, ponieważ kod JavaScript jest wykonywany po stronie klienta, podczas gdy kod Java jest wykonywany po stronie serwera. W tym procesie tracisz zmienne środowiska wykonawczego. Będziesz musiał wywołać Java za pomocą żądania 'POST' lub' GET', przekazując twoje dane jako parametr żądania. – FK82

+0

@ FK82 - Rhino to interpreter JavaScript napisany w Javie (jest zawarty w JVM Java 6 jako część skryptowego API). – McDowell

+0

@McDowell: OP nie był określony z którego środowiska wykonawczego próbował wywołać funkcję Rhino/JavaScript. – FK82

Odpowiedz

9

implementować interfejs:

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"); 
    } 
} 
+0

Myślę, że nie chodziło o to, jak wywołać metodę Java z Javascript - dla której podałeś przykład, ale jak przekazać funkcję JavaScript do metody Java i wywołać funkcję z kodu Java. –

+1

@ Christiana Semrau - implementacja interfejsu powinna wywoływać funkcję JavaScript (gdzie nazywam 'print') – McDowell

+0

McDowell jest poprawny. Dzięki! Metoda callFromRhino może być zdefiniowana w ten sposób i działa! publiczny void callFromRhino (wywoływanie zwrotne działające) { callback.run(); } – sproketboy

7

sun.org.mozilla.javascript.internal.InterpretedFunction implementuje interfejs sun.org.mozilla.javascript.Function. Interfejs ten jest sposób na wywołana call które ma:

  • Context
  • Scriptable użyć jako zakres
  • Scriptable użyć jako wartości this w funkcji
  • oraz świeże z Objects, które są argumenty dla funkcji

Więc sugeruję, że w java jesteś cas t obiekt został przekazany jako sun.org.mozilla.javascript.Function i zadzwoń pod numer call. Pierwsze dwa argumenty mogą być tym, czego używałeś w Javie do uruchomienia skryptu w pierwszej kolejności. Sposób, w jaki go tam używasz, dwa ostatnie argumenty mogą być null i new Object[0].

+0

Funkcja sun.org.mozilla.javascript.Function nie jest dostępna w wbudowanym silniku Rhino w Javie 6. Zrobię to za pomocą możliwego do pobrania słoika z nosorożcem. – sproketboy

+0

Należy zauważyć, że w słoiku Rhino, który można pobrać, interfejs nazywa się "org.mozilla.javascript.Function" - Sun zmienił nazwę wszystkich interfejsów w wersji, którą wysyłają w swoim JDK. –

2

Rozwiązaniem jest faktycznie powołać go w innym scenariuszu. Tego rodzaju prace:

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 
    } 
} 

Po uzyskaniu odwołania do funkcji należy poprosić silnik o wykonanie tej funkcji. I choć nie jest ładna, zadając js eval() dla ciebie z określonym zestawem powiązań, faktycznie wykona to zadanie za ciebie. Musisz uważać, aby zmienne, którymi manipulujesz, należały do ​​właściwego zakresu; Myślę, że łatwo tu popełnić błędy.

+0

Dzięki ciekawe. – sproketboy

+0

Nie ma za co. Walczyłem z tym samym problemem i nie znalazłem satysfakcjonującej odpowiedzi na twoje pytanie, więc czułem, że uzasadniona była właściwa odpowiedź. Od czasu odpowiedzi potwierdziłem, że działa to naprawdę dobrze i wydaje się, że nie jest trudno mieć callbacki wywołujące java, wywołujące funkcje z parametrami. To naprawdę fajne! Zastanawiam się, czy możliwe jest przeniesienie pliku node.js do nosorożca. lol. – mogsie

1

Ten przykład obejmuje implementowanie interfejsu java za pomocą javascript. To również może być użyte do wywołania wywołań zwrotnych javascript z 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); "); 
    } 
}