При переносе проекта C # на Java, который использует JavaScript для пользовательских сценариев, существует класс с перегруженным методом:
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()
из Scriptable
:
get(name = "FindNodeByID")
get(name = "__noSuckMethod__")
get(name = "toString")
get(name = "valueOf")
Чтобы исправить это, мы можем создать определенные FunctionObject
объекты, чтобы Rhino знал, что FindNodeByID является функцией некоторого фрагмента кода Java. (Хотя я пытался сделать это вручную, простое использование Scriptable.defineFunctionProperties
делает это автоматически в гораздо меньшем количестве кода.) Это работает хорошо, пока мы не достигнем перегруженных функций GetChild, когда получим это исключение:
org.mozilla.javascript.EvaluatorException: Method "GetChild" occurs multiple times in class "TreeNode".
В качестве альтернативы ScriptableObject.defineClass(scope, TreeNode.class)
отобразит функции jsFunction_*
в JaavScript. Однако это приводит к тому же виду ошибки:
org.mozilla.javascript.EvaluatorException: Invalid method "jsFunction_GetChild": name "GetChild" is already in use.
Наконец, я посмотрел на добавление логики внутри get()
, чтобы попытаться выбрать, какой FunctionObject
мы хотим, и вернуться в Rhino. Тем не менее, вам не предоставлена какая-либо параметризация функции или какой-либо способ смотреть вперед, кроме как очень хакерским, громоздким способом.
Я что-то упустил? Есть ли способ как индексировать в сопоставленный объект Java в Rhino, так и перегружать функции Java? Rhino явно поддерживает их обоих и наверняка поддерживает их вместе, но не кажется очевидным, как это сделать.
Спасибо за любые идеи!