Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Bug with ambiguous methods using varargs?

I have a class with two methods like this:

public class Dummy{
  public void doIt(String arg1, File arg2, Writer... ctx){
    // Do something very important...
  }

  public void doIt(String arg1, Writer... ctx){
    // Do something else...
  }

  public static void main(String[] args){
    new Dummy().doIt("Test", null);
  }
}

I would expect, that the compiler would give an error, because the method call is ambiguous. Instead the second method is called.

In our case the ambigous methods are generated from database methods and the varargs where added later. Now we don't know how to avoid problems with method calls like in the example.

Does anybody else have this problem and an idea how to solve it?

like image 253
ThiesR Avatar asked Feb 07 '14 17:02

ThiesR


1 Answers

I'm giving the answer according to this:

The problem is how to find method calls like this, where the first method should be called (and was before we changed our code generator), but the second one is called.

First, as it is already has been pointed out, Java compiler gives warnings about such method usages. It looks like this:

com/stack/undsprlbl/varargs/Main.java:10: warning: non-varargs call of varargs method with inexact argument type for last parameter;

and could be easily grep-ed from javac output.

Second, you may consider writing some self-test for your code along these lines:

    Class cl = Ambiguity.class;
    Method[] methods = cl.getDeclaredMethods();
    Set<String> varargsMethods = new HashSet<String>();
    for (Method method : methods) {
        Class c[] = method.getParameterTypes();
        if(c.length > 0)
        {
            Class last = c[c.length - 1];
            if(last.isArray())
            {
                if(varargsMethods.contains(method.getName()))
                    System.out.println("Method " + cl.getName() + "#"+ method.getName() + " looks suspicious.");
                else
                    varargsMethods.add(method.getName());
            }
        }
    }

with understanding that you ought to iterate over all your classes instead of direct mentioning. This answer seems a way to go --- take all packages in the app and check them.

At this point you'll have two lists:

  1. List of ambiguous varargs method usages

  2. List of ambiguous varargs methods.

By crossing those two you can figure out where you probably will have problems.

Next, I would suggest checking out the version of the code before the second method was added and finding all the usages of the first one. Those clearly have to be disambiguated in favour of the first method in HEAD version. This way, I suppose, there would be quite finite number of those calls left.

like image 182
Undespairable Avatar answered Oct 05 '22 00:10

Undespairable