2010-05-15 44 views
9

Básicamente estoy tratando de pasar una función javaScript a un método Java para actuar como una devolución de llamada al script.¿Cómo puedo pasar una función javaScript a un Método Java para actuar como una devolución de llamada (Rhino)

Puedo hacerlo, más o menos, pero el objeto que recibo es sun.org.mozilla.javascript.internal.InterpretedFunction y no veo una forma de invocarlo.

¿Alguna idea?

Esto es lo que tengo hasta ahora:

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

¿Esto es un applet? Si no, es imposible ya que el código JavaScript se ejecuta en el lado del cliente, mientras que el código Java se ejecuta en el lado del servidor. Sus variables de tiempo de ejecución se pierden en ese proceso. Tendrá que llamar a Java a través de una solicitud 'POST' o' GET', pasando sus datos como un parámetro de solicitud. – FK82

+0

@ FK82 - Rhino es un intérprete de JavaScript escrito en Java (está incluido en Java 6 JVM como parte de la API de scripts). – McDowell

+0

@McDowell: El OP no era específico de qué tiempo de ejecución intentaba llamar a la función Rhino/JavaScript. – FK82

Respuesta

9

implementar una interfaz:

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

Creo que la pregunta no fue cómo invocar un método Java desde Javascript, para el cual usted dio un ejemplo, sino cómo pasar una función Javascript a un método Java e invocar la función desde el código Java. –

+1

@Christian Semrau: la implementación de la interfaz debe invocar la función de JavaScript (donde llamo 'imprimir') – McDowell

+0

McDowell está en lo cierto. ¡Gracias! El método callFromRhino se puede definir así y ¡funciona! public void callFromRhino (devolución de llamada ejecutable) { callback.run(); } – sproketboy

7

sun.org.mozilla.javascript.internal.InterpretedFunction implementa la interfaz sun.org.mozilla.javascript.Function. Ese interfaz tiene un método en que llamó call que lleva:

  • un Context
  • un Scriptable de usar como el alcance
  • un Scriptable para usar como el valor de this dentro de la función
  • una matriz de Objects que son los argumentos para la función

Entonces, lo que sugiero es que en java usted cas t el objeto que recibió como sun.org.mozilla.javascript.Function y llame al call. Los primeros dos argumentos pueden ser lo que sea que haya usado desde Java para iniciar el script en primer lugar. La forma en que lo está utilizando allí, los dos últimos argumentos pueden ser null y new Object[0].

+0

La función sun.org.mozilla.javascript.function no está disponible en el motor de Rhino incorporado en Java 6. Lo haré con el contenedor de rinocerontes descargable. – sproketboy

+0

Tenga en cuenta que en el jar de Rhino descargable, la interfaz se llama 'org.mozilla.javascript.Function' - Sun renombró todas las interfaces en la versión que envían en su JDK. –

2

La solución es en realidad para invocar en otro guión. Este tipo de trabajos:

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

Al llegar de nuevo la referencia a una función, tiene que solicitar al motor para ejecutar esa función para usted. Y aunque no es bonito, pedir js a eval() para usted con un conjunto específico de enlaces realmente hará el trabajo por usted. Debe tener cuidado de que las variables que está manipulando pertenezcan al alcance correcto; Supongo que es fácil cometer errores aquí.

+0

Gracias interesante. – sproketboy

+0

De nada. Estaba luchando con el mismo problema y no encontré una respuesta satisfactoria a su pregunta, por lo que sentí que se justificaba una respuesta. Desde la respuesta, he verificado que esto funciona muy bien, y aparentemente no es difícil tener devoluciones de llamadas que llamen a java, llamando a funciones con parámetros. ¡Es bastante genial! Me hace preguntarme si es posible portar node.js a rhino. lol. – mogsie

1

Este ejemplo cubre la implementación de la interfaz java con javascript. Eso también se puede usar para la invocación de devoluciones de llamada javascript desde 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); "); 
    } 
} 

 
Cuestiones relacionadas