2010-05-15 3 views
9

Fondamentalement, j'essaie de passer une fonction javaScript à une méthode Java pour agir comme un rappel au script.Comment puis-je passer une fonction javaScript à une méthode Java pour agir comme un rappel (Rhino)

Je peux le faire - en quelque sorte - mais l'objet que je reçois est un sun.org.mozilla.javascript.internal.InterpretedFunction et je ne vois pas comment l'invoquer.

Des idées?

Voici ce que j'ai jusqu'à présent:

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

Est-ce une applet? Sinon, c'est impossible car le code JavaScript est exécuté côté client, tandis que le code Java est exécuté côté serveur. Vos variables d'exécution sont perdues dans ce processus. Vous devrez appeler le Java via une requête 'POST' ou' GET', en passant vos données en tant que paramètre de requête. – FK82

+0

@ FK82 - Rhino est un interpréteur JavaScript écrit en Java (il est inclus dans la JVM Java 6 dans le cadre de l'API de script). – McDowell

+0

@McDowell: L'OP n'était pas spécifique à partir de quel runtime il essayait d'appeler la fonction Rhino/JavaScript. – FK82

Répondre

9

implémentent une interface:

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

Je pense que la question n'était pas comment appeler une méthode Java de Javascript - pour laquelle vous avez donné un exemple, mais comment passer une fonction Javascript à une méthode Java et invoquer la fonction du code Java. –

+1

@ Christian Semrau - l'implémentation de l'interface devrait invoquer la fonction JavaScript (où j'appelle 'print') – McDowell

+0

McDowell est correct. Merci! La méthode callFromRhino peut être définie comme ça et ça marche! Public void callFromRhino (callback exécutable) { callback.run(); } – sproketboy

7

sun.org.mozilla.javascript.internal.InterpretedFunction implémente l'interface sun.org.mozilla.javascript.Function. Cette interface a une méthode sur elle appelée call qui prend:

  • un Context
  • un Scriptable à utiliser comme la portée
  • un Scriptable à utiliser comme valeur de this dans la fonction
  • un tableau de Objects qui sont les arguments à la fonction

Donc, ce que je suggère est que java vous cas t l'objet vous a été passé comme sun.org.mozilla.javascript.Function et appelez call. Les deux premiers arguments peuvent être tout ce que vous avez utilisé de Java pour commencer le script en premier lieu. La façon dont vous l'utilisez ici, les deux derniers arguments peuvent être null et new Object[0].

+0

La fonction sun.org.mozilla.javascript.Function n'est pas disponible dans le moteur Rhino intégré dans Java 6. Je le ferai avec le fichier rhino téléchargeable. – sproketboy

+0

Notez que dans le jar Rhino téléchargeable, l'interface est appelée 'org.mozilla.javascript.Function' - Sun renommé toutes les interfaces dans la version qu'ils livrent dans leur JDK. –

2

La solution est en fait de l'invoquer dans un autre script. Ce genre de travaux:

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

Quand vous revenez la référence à une fonction, vous devez demander au moteur d'exécuter cette fonction pour vous. Et bien que ce ne soit pas joli, demander à js de l'évaluer() pour vous avec un ensemble spécifique de reliures fera effectivement le travail pour vous. Vous devez veiller à ce que les variables que vous manipulez appartiennent à la bonne portée; Je suppose qu'il est facile de faire des erreurs ici.

+0

Merci intéressant. – sproketboy

+0

De rien. Je me débattais avec le même problème et je n'ai pas trouvé de réponse satisfaisante à votre question, alors j'ai pensé qu'une réponse de travail était justifiée. Depuis la réponse j'ai vérifié que cela fonctionne très bien, et il n'est apparemment pas difficile d'avoir des callbacks appelant Java, appelant des fonctions avec des paramètres. C'est vraiment cool! Je me demande s'il est possible de porter node.js à rhino. lol. – mogsie

1

Cet exemple couvre l'implémentation de l'interface java avec javascript. Cela peut également être utilisé pour l'appel des callbacks javascript de 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); "); 
    } 
} 

 
Questions connexes