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

时间:2022-11-25 08:42:21

I have a simple Java class that has some methods:

我有一个简单的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) {
        // ....
    }
}

I would like to create an instance of this class and allow the Javascript code to call the methods directly, like so:

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

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.

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

3 个解决方案

#1


7  

I'm not real familiar with Rhino, but something like this should work:

我对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);
      };
    })();
  }
}

Just loop over the properties of utils,and for each one that is a function, create a global function that calls it.

只需循环utils的属性,对于每个作为函数的属性,创建一个调用它的全局函数。

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:

编辑:我在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()))

#2


3  

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.

我不确定这将如何使用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));

The documentation is available at https://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/FunctionObject.html.

该文档可在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).

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

#3


0  

This is possible if you use the rhino API rather than the ScriptEngine API as explained in this answer: https://*.com/a/16479685/1089998.

如果您使用rhino API而不是本文解释的ScriptEngine API,这是可能的:https://*.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.

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

I have a working example here:

我这里有一个工作示例:

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

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

#1


7  

I'm not real familiar with Rhino, but something like this should work:

我对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);
      };
    })();
  }
}

Just loop over the properties of utils,and for each one that is a function, create a global function that calls it.

只需循环utils的属性,对于每个作为函数的属性,创建一个调用它的全局函数。

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:

编辑:我在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()))

#2


3  

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.

我不确定这将如何使用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));

The documentation is available at https://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/FunctionObject.html.

该文档可在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).

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

#3


0  

This is possible if you use the rhino API rather than the ScriptEngine API as explained in this answer: https://*.com/a/16479685/1089998.

如果您使用rhino API而不是本文解释的ScriptEngine API,这是可能的:https://*.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.

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

I have a working example here:

我这里有一个工作示例:

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

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