如何使用Rhino将Java类中的方法添加为Javascript中的全局函数?

问题描述 投票:13回答:4

我有一个简单的Java类,其中包含一些方法:

public class Utils {
    public void deal(String price, int amount) {
        // ....
    }
    public void bid(String price, int amount) {
        // ....
    }
    public void offer(String price, int amount) {
        // ....
    }
}

我想创建此类的实例,并允许Javascript代码直接调用方法,如下所示:

deal("1.3736", 100000);
bid("1.3735", 500000);

我目前只能弄清楚的唯一方法是使用

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
engine.put("utils", new Utils());

,然后在Javascript代码中使用utils.deal(...)。我还可以使用Javascript为每个方法编写包装函数,但是应该有一种更简单的方法来自动为类的所有公共方法进行此操作。

java javascript rhino
4个回答
7
投票

我对Rhino不是很熟悉,但是这样的方法应该可以工作:

for(var fn in utils) {
  if(typeof utils[fn] === 'function') {
    this[fn] = (function() {
      var method = utils[fn];
      return function() {
         return method.apply(utils,arguments);
      };
    })();
  }
}

仅循环访问utils的属性,并为每个作为函数的对象创建一个调用它的全局函数。

编辑:我在Groovy脚本中完成了此工作,但是我必须在绑定中设置utils,而不是像在您的代码中那样在引擎上设置utils:

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()))

4
投票

我不确定使用JSR-223 API会如何工作,但是使用Rhino API,您可以使用要添加的方法创建FunctionObject,如下所示。

Class[] parameters = new Class[] { String.class, Integer.class };
Method dealMethod = Utils.class.getMethod("deal", parameters);
engine.put("deal", new FunctionObject("deal", dealMethod, scope));

该文档位于https://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/FunctionObject.html

[您可能需要引用Rhino库来访问FunctionObject类,但我不确定如何使用JSR-223 API获得scope对象(尽管null可能会起作用)。


0
投票

如果您使用rhino API而不是如本答案所述的[ScriptEngine API:https://stackoverflow.com/a/16479685/1089998,则可以这样做。

我比Noah的答案更喜欢这种方法,因为它意味着您不需要在每次执行之前执行随机的javascript代码。

我在这里有一个有效的示例:

https://github.com/plasma147/rhino-play


0
投票

使用Java Lambdas(因此从1.8开始,实际上可以做到这一点:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
BiConsumer<String, Integer> deal = Utils::deal
engine.put("deal", deal);
© www.soinside.com 2019 - 2024. All rights reserved.