在将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显然都支持他们,并且肯定会支持他们,但是如何做到这一点似乎并不明显。
感谢您的任何想法!
答案 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。