13

我有一个简单的 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());

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

4

4 回答 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,而不是像在你的代码中那样在引擎上设置:

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()))
于 2010-03-31T15:03:17.113 回答
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该类,并且我不确定您将如何scope使用 JSR-223 API 获取对象(尽管它可能null会起作用)。

于 2010-03-31T14:56:16.593 回答
0

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

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

我在这里有一个工作示例:

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

于 2013-10-05T11:11:06.500 回答
0

使用 Java Lambdas(从 1.8 开始)实际上可以这样做:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
BiConsumer<String, Integer> deal = Utils::deal
engine.put("deal", deal);
于 2019-12-20T17:44:47.107 回答