cbuschka / beanshell2

Automatically exported from code.google.com/p/beanshell2
0 stars 0 forks source link

BSH calling Java calls randomly an ambiguous method if var args are involved #83

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1. Modify VarargsTest as below, adding 
calling_java_varargs_or_without_should_choose_the_simplest() and the two 
overloaded methods in ClassWithVarargMethods
2. Run in Eclipse the tests from VarargsTest. My environment is eclipse 4.2 
under XP 32bits and JDK 1.7.0_7.

What is the expected output? What do you see instead?

The new test should succeed calling the simplest method being a match for two 
strings (returning 2). In my case it fails (returning 3). If I swap the two 
overloaded methods it succeeds.
If it works for you initially, swap them, retry... Junit 4.10 and J7 also 
introduces some randomness in the order the tests are executed.
Anyway. It can fail.

Yes the two methods are technically a valid match for 
helper.twoChoices("one","two").
However, like in Java you would expect the best match to be called.
What I would expect here would be to have the BSF code getting a list of all 
the matching methods and taking the closest match, not the first. It seems that 
filtering by argument types works well.

If multiple methods are a match then take the one with the least number of 
arguments.
The current behavior is random as the first match is the good one.
If you have more than one choice then I do not know.

However on my production system, in some cases the first method is called, in 
some other the second without even restarting the VM !!!

The reason is that the reflection API does not guaranty at all in which order 
the (matching/all) methods are returned for a class. 
Picking the one with the smaller number of arguments may not be totally perfect 
but this will bring a little bit of repeatability.

Thanks

public class VarargsTest {
...        

@Test
public void calling_java_varargs_or_without_should_choose_the_simplest() throws 
Exception {
    final Interpreter interpreter = new Interpreter();
    interpreter.set("helper", new ClassWithVarargMethods());
    @SuppressWarnings({"unchecked"})
    final int argPassedIn = (int) interpreter.eval("helper.twoChoices(\"one\",\"two\")");
    Assert.assertEquals("Not picking the simplest choice",2,argPassedIn);
}

public static class ClassWithVarargMethods {
    ...
    /** I DO NOT expect string/string/varargs to be called */
    public int twoChoices(final String string1, final String string2, final Object ... args) {
        return 3;
    }
    /** I expect string/string to be called */
    public int twoChoices(final String string1, final String string2) {
        return 2;
    }
    ...
}

Original issue reported on code.google.com by dupuy.ol...@gmail.com on 12 Nov 2012 at 9:43

GoogleCodeExporter commented 8 years ago
Looking at it more closely in my case (2 static methods but the bug can be 
reproduced with member methods) the stack is :
- bsh.Reflect.gatherMethodsRecursive(baseClass, methodName, types.length, 
publicMethods, nonPublicMethods) returns the 2 methods "inputDialog" in a 
random order (reflection makes no guaranty on the order)
- the 2 methods are passed in to bsh.Reflect.findMostSpecificMethod(Class[] 
idealMatch, List<Method> methods)
- this one calls bsh.Reflect.findMostSpecificSignature(Class[] idealMatch, 
Class[][] candidates) and this one sometimes makes the bad choice.

Regarding the unit test upper, you can add a giant loop around (e.g. 10000 
loops) to increase the chance of failure and you should see that sometimes the 
test is OK and sometimes fails.

Original comment by dupuy.ol...@gmail.com on 14 Nov 2012 at 2:32