Ошибка Java с неоднозначными методами с использованием varargs?

У меня есть класс с двумя способами:

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);
  }
}

Я бы ожидал, что компилятор даст ошибку, потому что вызов метода неоднозначен. Вместо этого вызывается второй метод.

В нашем случае неоднозначные методы генерируются из методов базы данных и varargs, которые добавляются позже. Теперь мы не знаем, как избежать проблем с вызовами методов, как в примере.

У кого-нибудь еще есть эта проблема и идея, как ее решить?

Ответ 1

Я даю ответ в соответствии с этим:

Проблема заключается в том, как найти вызовы методов, подобные этому, где первый метод должен быть вызван (и был до того, как мы изменили наш код генератор), но вызывается вторая.

Во-первых, как уже было указано, компилятор Java дает предупреждения об использовании такого метода. Это выглядит так:

com/stack/undsprlbl/varargs/Main.java: 10: предупреждение: вызов без varargs varargs метод с неточным аргументом типа для последнего параметра;

и может быть легко grep -ed от javac вывода.

Во-вторых, вы можете подумать о написании некоторого самотестирования для своего кода в следующих строках:

    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());
            }
        }
    }

с пониманием, что вы должны перебирать все свои классы вместо прямого упоминания. Этот ответ кажется способ пойти - возьмите все пакеты в приложении и проверьте их.

На этом этапе у вас будет два списка:

  • Список способов использования двусмысленных методов varargs

  • Список двусмысленных методов varargs.

Скрещивая эти два, вы можете выяснить, где вы, вероятно, будете иметь проблемы.

Далее я бы предложил проверить версию кода до того, как был добавлен второй метод, и найти все способы использования первого. Это явно необходимо устранить в пользу первого метода в версии HEAD. Таким образом, я полагаю, оставалось бы довольно конечное число этих вызовов.

Ответ 2

Ответ на ваш конкретный вопрос - это сделать то, что сказали другие, и вызвать doIt("someString", null, null), чтобы сделать вызов метода более конкретным.

Это, как говорится, РЕАЛЬНЫЙ ответ состоит в том, чтобы просто переписать методы, чтобы взять коллекцию в качестве аргумента. Использование varargs имеет тенденцию вызывать больше проблем, чем решает.

Ответ 3

Я бы предложил создать недвусмысленный класс-оболочку, чтобы предотвратить случайное неправильное использование сгенерированного класса.

Пример Wrapper:

public class NicerDummy{
    Dummy dummy;
    public NicerDummy(){
        dummy = new Dummy(); 
    }

    public void doSomething(String arg1, Writer... ctx){
        dummy.doIt(arg1, Writer);
    }

    public void doSomethingElse(String arg1, File arg2, Writer... ctx){
        dummy.doIt(arg1, arg2, ctx);
    }
}