2010-05-15 10 views
9

Fondamentalmente sto provando a passare una funzione javaScript a un metodo Java per fungere da callback per lo script.Come passare una funzione javaScript a un metodo Java per agire come callback (Rhino)

Posso farlo - una specie di - ma l'oggetto che ricevo è una funzione sun.org.mozilla.javascript.internal.Interpreted e non vedo il modo di invocarlo.

Qualche idea?

Ecco quello che ho finora:

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

È un'applet? In caso contrario è impossibile poiché il codice JavaScript viene eseguito lato client, mentre il codice Java viene eseguito lato server. Le variabili di runtime sono perse in quel processo. Dovrai chiamare Java tramite una richiesta 'POST' o' GET', passando i tuoi dati come parametro di richiesta. – FK82

+0

@ FK82 - Rhino è un interprete JavaScript scritto in Java (è incluso in Java 6 JVM come parte dell'API dello script). – McDowell

+0

@McDowell: L'OP non era specifico da quale runtime stava cercando di chiamare la funzione Rhino/JavaScript. – FK82

risposta

9

implementare un'interfaccia:

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

Penso che la domanda non fosse come invocare un metodo Java da Javascript - per il quale è stato fornito un esempio, ma come passare una funzione Javascript a un metodo Java e richiamare la funzione dal codice Java. –

+1

@Christian Semrau - l'implementazione dell'interfaccia dovrebbe richiamare la funzione JavaScript (dove chiamo 'print') – McDowell

+0

McDowell è corretta. Grazie! Il metodo callFromRhino può essere definito in questo modo e funziona! public void callFromRhino (callback eseguibile) { callback.run(); } – sproketboy

7

sun.org.mozilla.javascript.internal.InterpretedFunction implementa l'interfaccia sun.org.mozilla.javascript.Function. Questa interfaccia ha un metodo sopra definito call che prende:

  • un Context
  • un Scriptable da utilizzare come ambito
  • un Scriptable da utilizzare come valore this all'interno della funzione
  • un array di Objects che sono gli argomenti della funzione

Quindi, quello che suggerisco è che in Java si t l'oggetto in cui sei stato passato come sun.org.mozilla.javascript.Function e chiama call. I primi due argomenti possono essere qualsiasi cosa tu abbia usato da java per avviare lo script in primo luogo. Il modo in cui lo stai usando li, gli ultimi due argomenti possono essere null e new Object[0].

+0

La funzione sun.org.mozilla.javascript.Function non è disponibile nel motore Rhino integrato in Java 6. Lo farò con il barattolo del rinoceronte scaricabile. – sproketboy

+0

Si noti che nel contenitore Rhino scaricabile, l'interfaccia si chiama 'org.mozilla.javascript.Function' - Sun ha rinominato tutte le interfacce nella versione che vengono fornite nel proprio JDK. –

2

La soluzione è in realtà per invocarlo in un altro script. Questo tipo di opere:

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

Quando si ottiene indietro il riferimento a una funzione, è necessario chiedere al motore di eseguire quella funzione per voi. E anche se non è bello, chiedendo a js di eval() per te con una serie specifica di binding, in realtà farà il lavoro per te. Devi stare attento che le variabili che stai manipolando appartengano allo scope corretto; Immagino sia facile commettere errori qui.

+0

Grazie interessante. – sproketboy

+0

Prego. Stavo lottando con lo stesso problema e non ho trovato una risposta soddisfacente alla tua domanda, quindi ho sentito che una risposta funzionante era giustificata. Dalla risposta ho verificato che funziona molto bene, e apparentemente non è difficile avere dei callback che chiamano java, chiamando le funzioni con i parametri. E 'veramente forte! Mi chiedo se sia possibile portare node.js in rhino. lol. – mogsie

1

Questo esempio copre l'implementazione dell'interfaccia java con javascript. Questo può anche essere usato per invocare javascript callback da 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); "); 
    } 
} 

 
Problemi correlati