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

Posted

技术标签:

【中文标题】如何使用 Rhino 将 Java 类中的方法添加为 Javascript 中的全局函数?【英文标题】:How can I add methods from a Java class as global functions in Javascript using Rhino? 【发布时间】:2011-02-02 21:12:18 【问题描述】:

我有一个简单的 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 是两种完全不同的语言。它们可能具有类似的类 C 语法,但它们并不相同。 Rhino 是一个用于 Java 的嵌入式 js 引擎。这种事情应该是可以实现的。我在 Perl 中使用 SpiderMonkey 管理它:blog.dorward.me.uk/2006/02/02/spambots_that_drink_coffee.html @thecoshman 这是一个绝对有效的问题。您可以在 Java 中运行 Javascript,然后您可能需要在 JS 中使用 Java 好东西。 【参考方案1】:

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

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
BiConsumer<String, Integer> deal = Utils::deal
engine.put("deal", deal);

【讨论】:

【参考方案2】:

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

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

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

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

【讨论】:

【参考方案3】:

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

【讨论】:

+1 很好地使用了闭包。我想我会接受你的解决方案。 如何让它在 Java 中工作?您会使用以下内容: ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); engine.put("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 可能会工作)。

【讨论】:

我认为这不会起作用,因为 deal 函数对象没有对实例的引用。 @Geoff:我假设它们是静态方法,因为它们会在没有(JavaScript)this 对象的情况下被调用。再看一遍,我猜他们不是,但可能应该是。 谢谢。实际上,当使用 Rhino API 时,Context 类有一个 javaToJS 方法,这正是我所需要的。看起来它也应该与非静态方法一起使用。我希望有一个 JSR-223 解决方案,但我认为没有。 感谢您,Rhino 文档对这部分内容过于不清楚

以上是关于如何使用 Rhino 将 Java 类中的方法添加为 Javascript 中的全局函数?的主要内容,如果未能解决你的问题,请参考以下文章

将监听器添加到 Java 类中的方法

Rhino 中的 XMLHttpRequest?

使用 Rhino(Mozilla 的 rhino)的优点

用 Rhino 解释 Java 中的 JavaScript:暂停/恢复脚本

如何使用 Rhino Mocks 模拟任意行为?

Rhino:如何从 Java 调用 JS 函数