1

I pass a function from JavaScript file into Java code. JavaScript function looks like:

entity.handler = function(arg1, arg2) {
    //do something
};

In Java code the class implements the Scriptable interface. And when I invoke the JavaScript, actually the following method is invoked in Java:

Scriptable.put(java.lang.String s, org.mozilla.javascript.Scriptable scriptable, java.lang.Object o)

where for my case:

s = 'handler';

scriptable - object whose type is com.beanexplorer.enterprise.operations.js.ScriptableEntity

o - actually is a function, its type is org.mozilla.javascript.gen.c15, ( o instanceof Scriptable ) returns true in debugger.

In the Scriptable.put() method implementation I want to delegate action to the 'o' object:

SomeClass.invoke( new SomeListener(){
    @override
    public void someAction(int arg1, float arg2) {
       //here I need to delegate to the 'o' object.
       //do something looked like: 
       o.call(arg1, arg2); // have no idea how to do it, if it's possible.
    }
}

How can I do it? I cannot find any example needed for my case.

Thanks.

EDIT, solution: Actully o - could be cast to Function. As a result the following solution helped:

@Override
put(java.lang.String s, org.mozilla.javascript.Scriptable scriptable, java.lang.Object o) {
    ....
    final Function f = ( Function )o;
    final SomeInterface obj = new ...;
    obj.someJavaMethod( Object someParams, new SomeJavaListener() { 
        @Override
    public void use(Object par1, Object par2) throws Exception {
        Context ctx = Context.getCurrentContext();
        Scriptable rec = new SomeJavaScriptableWrapperForObject( par1);
            f.call( ctx, scriptable, scriptable, new Object[] { rec, par2 } );
        }
});
Alexandr
  • 9,213
  • 12
  • 62
  • 102
  • From the [API doc of Scriptable](http://www.jarvana.com/jarvana/view/rhino/js/1.6R6/js-1.6R6-javadoc.jar!/org/mozilla/javascript/Scriptable.html): `Host system implementors may find it easier to extend the ScriptableObject class rather than implementing Scriptable when writing host objects.` I'd try that... – ppeterka Mar 13 '13 at 15:17
  • If I get you right, you offer to extend ScriptableObject by the Java class instead of implementing the interface. But anyway I have to override the put method, cause standard implementation does not suite. As a result I cannot see any benefits from extending the ScriptableObject class instead of implementing the interface. – Alexandr Mar 13 '13 at 15:23
  • Your argument is partly valid. I would however do that, because doing so, your code will be cleaner, and it might help discovering the cause of the problem, and this way you don't have to write all that code to get going... You only have to override the "useful" methods then... – ppeterka Mar 13 '13 at 15:43
  • May I ask what you are trying to do exactly? Not sure, because your question is ambiguous. As I understand it, you want to make your program scriptable, by allowing users to pass arbitrary code for `entity.handler`, which must be a function with arity 2. Is this all you want? – Raffaele Mar 13 '13 at 16:35
  • Yes, you are right. Originally it's not my code. The main purpose - to write handlers in JavaScript without knowing how they are actually processed. – Alexandr Mar 13 '13 at 23:14

1 Answers1

0

I managed to run your Javascript via the following code:

public class Main {

    public static void main(String[] args) {
        new ContextFactory().call(new ContextAction(){

            @Override
            public Object run(Context ctx) {
                Scriptable scope = ctx.initStandardObjects();
                try {
                    Scriptable entity = ctx.newObject(scope);

                    scope.put("console", scope, Context.javaToJS(System.out, scope));
                    scope.put("entity", scope, entity);

                    ctx.evaluateReader(
                        scope,
                        new InputStreamReader(Main.class.getResourceAsStream("/handler.js")),
                        "handler.js", 1, null);

                    Function handler = (Function) entity.get("handler", entity);
                    Object result = handler.call(ctx, scope, scope, new Object[] {"Foo", 1234});

                    System.out.println("Handler returned " + result);
                } catch (Exception e) {
                    e.printStackTrace(System.err);
                }
                return null;
            }
        });

    }
}

The following script must be available in a handler.js on your CLASSPATH:

entity.handler = function(arg1, arg2) {
    console.println("Hello world from the JS handler");
    return 42;
}
Raffaele
  • 20,627
  • 6
  • 47
  • 86