如何使用Rhino桥接包含重载方法的Java类并且可以在JavaScript中编制索引?

时间:2011-10-26 19:24:28

标签: java javascript rhino

在将C#项目移植到使用JavaScript作为用户脚本的Java时,有一个类具有重载方法:

public class TreeNode {
    public TreeNode GetChild(int index) { ... }
    public TreeNode GetChild(String childName) { ... }
    public TreeNode GetChild(String targetAttributeName, String targetAttributeValue) { ... }
    ...
}

使用Rhino,我可以在Java和JavaScript之间用以下内容桥接这个对象:

ScriptableObject.putProperty(scope, "TreeNode", Context.javaToJS(new TreeNode(), scope));

这对于简单地调用函数的脚本非常有用(并且所有重载的函数都可以正确地解析为正确的类型)。但是,C#应用程序也会索引到TreeNode中。例如,JavaScript用户函数是:

function NumericButtonClick() {
    screen = TreeNode.FindNodeById("Screen");
    screen["Text"] = screen["Text"] + Source["Text"];
}

运行此JavaScript代码会产生预期的Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EvaluatorException: Java class "TreeNode" has no public instance field or method named "Text".


要解决此问题,Rhino通过允许您实现Scriptable接口(或扩展包含一堆常见样板代码的ScriptableObject)来支持此功能。在这之后,绑定似乎消失了:

Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object.

调试代码,具体的互动是Rhino对get()的{​​{1}}方法进行四次调用:

Scriptable

要解决这个问题,我们可以创建特定的get(name = "FindNodeByID") get(name = "__noSuckMethod__") get(name = "toString") get(name = "valueOf") 对象,让Rhino知道FindNodeByID是某些Java代码的函数。 (虽然我已尝试手动执行此操作,但只需使用FunctionObject即可在少量代码中自动执行此操作。)当我们遇到重载的GetChild函数时,这很有效,当我们得到此异常时:

Scriptable.defineFunctionProperties

或者,org.mozilla.javascript.EvaluatorException: Method "GetChild" occurs multiple times in class "TreeNode". 会将ScriptableObject.defineClass(scope, TreeNode.class)函数映射到JaavScript中。但是,这会产生同样的错误:

jsFunction_*

最后,我考虑在org.mozilla.javascript.EvaluatorException: Invalid method "jsFunction_GetChild": name "GetChild" is already in use. 中添加逻辑,尝试选择我们想要的get()并返回Rhino。但是,除非以非常笨拙,麻烦的方式,否则不会提供任何功能的参数化或任何向前看的方式。


我错过了什么吗?有没有办法在Rhino中索引到映射的Java对象并重载Java函数? Rhino显然都支持他们,并且肯定会支持他们,但是如何做到这一点似乎并不明显。

感谢您的任何想法!

1 个答案:

答案 0 :(得分:1)

我不得不做类似的事情,在我试图弄清楚如何做的时候遇到了这个问题。

使用您在问题中提到的ScriptableObject.defineClass / jsFunction_方法为变量参数方法提供了一个解决方案。它在包含在rhino发行版中的Foo.java示例中进行了演示:

public static Object jsFunction_varargs(Context cx, Scriptable thisObj, Object[] args, Function funObj)

请注意,方法签名与上述内容匹配,因此它必须是静态的,因此您将拥有:

public static Object jsFunction_GetChild(Context cx, Scriptable thisObj, Object[] args, Function funObj)

在jsFunction_GetChild的主体中,你必须检查args以决定调用哪个版本的GetChild。在我的情况下,我有一个可变数量的args所以我只能检查args.length。在您的情况下,您似乎必须check the types。然后,在切换逻辑中,您可以将thisObj参数强制转换为类的类型(因为您的方法必须是静态的,您需要使用传入的引用来进行调用)以便调用并返回来自对GetChild。