Can I forcibly disambiguate overloaded methods called by Rhino?
Asked Answered
T

2

10

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?

Tonicity answered 21/11, 2011 at 6:11 Comment(0)
D
11

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.

Doable answered 21/11, 2011 at 13:22 Comment(1)
I agree... it would have been better if it just called the List one without failing like this. But Java 7 has broken quite a few other things in our application, this is just one of the many (the others, like the Locale changes, are all solved.)Tonicity
M
0

This is for overloaded constructors (Java Method Overloading and LiveConnect 3):

new java.lang.String["(char[])"](c)
Melindamelinde answered 18/5, 2017 at 9:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.