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

时间:2010-03-31 11:06:49

标签: java javascript rhino

我有一个简单的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中为每个方法编写包装函数,但应该有一种更简单的方法来自动为类的所有公共方法执行此操作。

4 个答案:

答案 0 :(得分: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()))

答案 1 :(得分: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可行。)

答案 2 :(得分:0)

如果您使用rhino API而不是ScriptEngine API,则可以使用此答案:https://stackoverflow.com/a/16479685/1089998

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

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

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

答案 3 :(得分:0)

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

import java.util.*;
public class Student
{
    Scanner werp = new Scanner(System.in);
    private String name;
    private LinkedList<Double> hwGrades = new LinkedList<Double>();
    private LinkedList<Double> testGrades = new LinkedList<Double>();
    private LinkedList<Double> labGrades = new LinkedList<Double>();
    private double hwGrade, testGrade, labGrade;
    private double hwCount = 0, testCount = 0, labCount = 0;
    private double hwSum = 0, labSum = 0, testSum = 0;
    private double finalGrade = 0;
    private char letterGrade = 'Q';

    public void Student(String n)
    {
        String name = n;
        LinkedList<Double> labGrades = new LinkedList<Double>();
        LinkedList<Double> hwGrades = new LinkedList<Double>();
        LinkedList<Double> testGrades = new LinkedList<Double>();
        double hwAvg = 0, testAvg = 0, labAvg = 0;
        double hwSum = 0, testSum = 0, labSum = 0;
        double hwCount = 0, testCount = 0, labCount = 0;
        double finalGrade = 0;
    }

    public void getGrades(LinkedList<Double> L, double count, double sum, double grade, String Z)
    {
        System.out.println("Enter the " + Z + " grades for " + name + "\n Mark the end of your answers with a negative number:");
        OUTER_LOOP:
        while(grade >= 0)
        {
            grade = werp.nextDouble();
            if (grade < 0 && grade != -1 || grade > 105) {System.out.println("Error! Incorrect scoring range" + "\n Enter a number between 0 and 105");}
            else if (grade == -1) {break OUTER_LOOP;}
            else
            {
                L.add(grade);
                count++;
                sum += grade;
            }
        }

    }
}