Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to use Rhino to bridge a Java class that contains overloaded methods and is indexable in JavaScript?
    primarykey
    data
    text
    <p>In porting a C# project to Java that uses JavaScript for user scripts, there's a class that has an overloaded method:</p> <pre><code>public class TreeNode { public TreeNode GetChild(int index) { ... } public TreeNode GetChild(String childName) { ... } public TreeNode GetChild(String targetAttributeName, String targetAttributeValue) { ... } ... } </code></pre> <p>Using Rhino, I can bridge this object between Java and JavaScript with:</p> <pre><code>ScriptableObject.putProperty(scope, "TreeNode", Context.javaToJS(new TreeNode(), scope)); </code></pre> <p>This works great for scripts that simply make calls to the functions (and all the overloaded functions get resolved to the correct type correctly). However, the C# application also indexes into the TreeNode. For example, a JavaScript user function is:</p> <pre><code>function NumericButtonClick() { screen = TreeNode.FindNodeById("Screen"); screen["Text"] = screen["Text"] + Source["Text"]; } </code></pre> <p>Running this JavaScript code results in the expected <code>Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EvaluatorException: Java class "TreeNode" has no public instance field or method named "Text".</code></p> <hr> <p>To fix this, Rhino supports this by allowing you implement the <code>Scriptable</code> interface (or extend the <code>ScriptableObject</code> which contains a bunch of common boilerplate code). After doing that, the binding seemingly disappears:</p> <pre><code>Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object. </code></pre> <p>Debugging the code, the specific interaction is that Rhino makes four calls to the <code>get()</code> method of <code>Scriptable</code>:</p> <pre><code>get(name = "FindNodeByID") get(name = "__noSuckMethod__") get(name = "toString") get(name = "valueOf") </code></pre> <hr> <p>To fix this, we can create specific <code>FunctionObject</code> objects to let Rhino know FindNodeByID is a function to some piece of Java code. (While I've tried doing it manually, just using <code>Scriptable.defineFunctionProperties</code> does this automatically in a lot less code.) This works well until we reach the overloaded GetChild functions, when we get this exception:</p> <pre><code>org.mozilla.javascript.EvaluatorException: Method "GetChild" occurs multiple times in class "TreeNode". </code></pre> <p>Alternatively, <code>ScriptableObject.defineClass(scope, TreeNode.class)</code> will map <code>jsFunction_*</code> functions into JaavScript. However, this generates the same sort of error:</p> <pre><code>org.mozilla.javascript.EvaluatorException: Invalid method "jsFunction_GetChild": name "GetChild" is already in use. </code></pre> <p>Finally, I looked at adding logic inside the <code>get()</code> to try and pick which <code>FunctionObject</code> we want and return in to Rhino. However, you're not provided any parametrization of the function or any way to look forward except in a very hacky, cumbersome way. </p> <hr> <p>Am I missing something? Is there any way to both index into a mapped Java object in Rhino and have overloaded Java functions? Rhino clearly supports them both, and surely supports them together, but it doesn't seem obvious how to do it.</p> <p>Thanks for any ideas!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload