Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I forcibly disambiguate overloaded methods called by Rhino?

Take the following test:

public static class Scripted {
    public void setThing(List<?> list) {
        System.out.println("Set via list");
    }

    public void setThing(Object[] array) {
        System.out.println("Set array");
    }
}

@Test
public void testScripting() throws Exception {
    ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
    engine.getContext().setAttribute("s", new Scripted(), ScriptContext.ENGINE_SCOPE);
    engine.eval("s.thing = Array(1, 2, 3);");
}

With the version of Rhino shipping with Java 7, if you run this, you will get an exception like this:

javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: The choice of Java constructor setThing matching JavaScript argument types (object) is ambiguous; candidate constructors are:
    void setThing(java.util.List)
    void setThing(java.lang.Object[]) (<Unknown source>#1) in <Unknown source> at line number 1

The Object[] overload existence in the first place is because the previous version of Rhino would not automatically convert arrays to List, but it would convert them to Object[].

If this were a personal project this is where I would just delete the Object[] overload. The problem is that this is a public API and there could be someone calling that method right now. I would still like to upgrade to Java 7 but I would like to avoid upsetting either the JavaScript users or the people using the array version of the method.

Is there a way to hide the Object[] overloaded methods from Rhino while others would still be able to call them?

like image 307
Hakanai Avatar asked Nov 21 '11 06:11

Hakanai


1 Answers

Although it's not very elegant there is a way of specifically calling one overloaded Java method. It is defined in the last section of the Java Method Overloading and LiveConnect 3 spec. Basically you use the whole signature of the method you want to call as it is displayed in the error message, using square brackets notation. In your case the following should work:

s["setThing(java.util.List)"](Array(1, 2, 3));

It's a bit unfortunate that the change we made with JavaScript arrays implementing java.util.List breaks existing code. Maybe it would be better to just pick one in case there are multiple matching methods.

like image 130
Hannes Wallnöfer Avatar answered Oct 15 '22 07:10

Hannes Wallnöfer