How can I add methods from a Java class as global functions in Javascript using Rhino?
I have a simple Java class that has some methods:
public class Utils {
public void deal(String price, int amount) {
// ....
}
public void bid(String price, int amount) {
// ....
}
public void offer(String price, int amount) {
// ....
}
}
I would like to create an instance of this class and allow t开发者_开发技巧he Javascript code to call the methods directly, like so:
deal("1.3736", 100000);
bid("1.3735", 500000);
The only way I could figure out for now was to use
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
engine.put("utils", new Utils());
and then use utils.deal(...)
in the Javascript code. I can also write wrapper functions in Javascript for each method, but there should be a simpler way to do this automatically for all the public methods of a class.
I'm not real familiar with Rhino, but something like this should work:
for(var fn in utils) {
if(typeof utils[fn] === 'function') {
this[fn] = (function() {
var method = utils[fn];
return function() {
return method.apply(utils,arguments);
};
})();
}
}
Just loop over the properties of utils
,and for each one that is a function, create a global function that calls it.
EDIT: I got this working in a Groovy script, but I had to set utils in the bindings, not on the engine like in your code:
import javax.script.*
class Utils {
void foo(String bar) {
println bar
}
}
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
engine.eval("""
for(var fn in utils) {
if(typeof utils[fn] === 'function') {
this[fn] = (function() {
var method = utils[fn];
return function() {
return method.apply(utils,arguments);
};
})();
}
}
foo('foo'); // prints foo, sure enough
""",new SimpleBindings("utils":new Utils()))
I'm not sure how this would work using the JSR-223 API, but with the Rhino API, you can create a FunctionObject
with the method you want to add like this.
Class[] parameters = new Class[] { String.class, Integer.class };
Method dealMethod = Utils.class.getMethod("deal", parameters);
engine.put("deal", new FunctionObject("deal", dealMethod, scope));
The documentation is available at https://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/FunctionObject.html.
You might need to reference the Rhino library to access the FunctionObject
class, and I'm not sure how you would get the scope
object with the JSR-223 API (although, it's possible that null
would work).
This is possible if you use the rhino API rather than the ScriptEngine API as explained in this answer: https://stackoverflow.com/a/16479685/1089998.
I prefer this approach over Noah's answer as it means you don't need to execute random javascript code before each execution.
I have a working example here:
https://github.com/plasma147/rhino-play
With Java Lambdas (so since 1.8) it is actually possible to just do this:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
BiConsumer<String, Integer> deal = Utils::deal
engine.put("deal", deal);
精彩评论