1

I'm currently attempting to declare functions dynamically in my Rhino JavaScript context. I have gotten to the point where I can declare variables/properties dynamically, but can't figure out how to pass a function as the value for a property. Here's how far I have gotten:

import java.lang.reflect.Member;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

public class Main {

    public static void main(String[] args) {

        Context jsContext = Context.enter();
        try {
            Scriptable scope = jsContext.initStandardObjects();
            ScriptableObject fooObject = new ScriptableObject() {

                @Override
                public String getClassName() {
                    return "MyFoo";
                }
            };

            scope.put("foo", scope, fooObject);
            fooObject.putProperty(fooObject, "oneProperty", "This is the value of oneProperty");

            Member myFunction = /* What goes here? */ null;
            fooObject.putProperty(fooObject, "doStuff", new FunctionObject("doStuff", myFunction, fooObject));

            Object resultProp = jsContext.evaluateString(scope, "foo.oneProperty", "<cmd>", 1, null);
            Object resultFunc = jsContext.evaluateString(scope, "foo.doStuff()", "<cmd>", 2, null);

            System.out.println("Property value: " + Context.toString(resultProp));
            System.out.println("Function value: " + Context.toString(resultFunc));
        }
        finally {
            jsContext.exit();
        }
    }

}

I think I am correctly defining the "foo" object within the global scope and setting the property oneProperty on it, but I can't figure out how to give that set method a function. Am I doing this correctly? How can I do it for a function?

UPDATE It looks like one can create a new class that implements the Function interface, implement the "call" method, and ignore the other methods that are required for that interface (just return null). That can then be given to the putProperty call. This seems to work, however it's painful to see in code and it is not clear from reading it what it does. I am still looking for a better solution, if one exists.

Wasabi Fan
  • 1,763
  • 3
  • 22
  • 36

1 Answers1

0

You can define a java class with some functions you want to bind to js. Then use class.getMethod to get the Method object to create a FunctionObject and finally put it to js scope.

Here 's a demo in Kotlin language:

class Container{
    companion object{
        @JvmStatic
        fun foo() = true
    }
}

val ctx: Context = Context.enter()
val scope = ctx.initStandardObjects()

val fMethod = Container::class.java.getMethod("foo")
val f = FunctionObject("foo", fMethod, scope)
scope.put("foo", scope, f)

ctx.evaluateString(scope, "foo()", "<cmd>", 1, null) // the result should be true

However, non static function will be much more complex, yuo can see this answer.

Chenhe
  • 924
  • 8
  • 19