Ссылка на метод неоднозначна при переходе с java8 на java9

Я переношу проект из JAVA 8 в JAVA 9, и у меня возникают проблемы с работой кода. Все работают в JAVA 8, но в 9 у меня возникают следующие ошибки:

Error java: reference to ok is ambiguous
      both method <T>ok(java.util.function.Supplier<T>)  and method ok(web.Procedure) match

вот код, когда я вызываю метод:

public ResponseEntity<List<MailTemplateDto>> mailTemplateFindAll() {
    return ok(() -> mailTemplateService.findAll());
}

и вот реализация:

 public <T> ResponseEntity<T> ok(Supplier<T> action) {
     return this.body(HttpStatus.OK, action);
 }

 public <T> ResponseEntity<T> ok(T body) {
     return this.ok(() -> {
         return body;
     });
 }

 public ResponseEntity<Void> ok(Procedure action) {
     action.invoke();
     return this.status(HttpStatus.OK);
 }

 public ResponseEntity<Void> ok() {
     return this.status(HttpStatus.OK);
 }

для интерфейса процедуры:

@FunctionalInterface
public interface Procedure {
    void invoke();
}

Любые идеи?


Воспроизводимый код::

public class Q48227496 {

    public A<?> test() {
        return ok(() -> System.out.append("aaa"));
    }

    private class A<T> {
    }

    private <T> A<T> ok(java.util.function.Supplier<T> action) {
        return new A<>();
    }

    public <T> A<T> ok(T body) {
        return new A<>();
    }

    private <T> A<T> ok(Procedure action) {
        return new A<>();
    }

    public <T> A<T> ok() {
        return new A<>();
    }

    @FunctionalInterface
    public interface Procedure {
        void invoke();
    }
}

Результатом следующей ошибки с компилятор::

error: reference to ok is ambiguous
        return ok(() -> System.out.append("aaa"));
               ^
  both method <T#1>ok(Supplier<T#1>) in Q48227496 and method <T#2>ok(Procedure) in Q48227496 match
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>ok(Supplier<T#1>)
    T#2 extends Object declared in method <T#2>ok(Procedure)

Ответ 1

Это ошибка.

Сообщено с идентификатором ошибки: JDK-8195598


Я упростил ваш пример далее:

public class Q48227496 {
    public CompletableFuture<?> test() {
        return ok(() -> System.out.append("aaa"));
    }
    public <T> CompletableFuture<T> ok(Supplier<T> action) {
        return CompletableFuture.supplyAsync(action);
    }
    public <T> CompletableFuture<T> ok(T body) {
        return CompletableFuture.completedFuture(body);
    }
    public CompletableFuture<Void> ok(Runnable action) {
        return CompletableFuture.runAsync(action);
    }
}

В версии выпуска Java 9 с "reference to ok is ambiguous" это не выполняется, указав "both method <T>ok(Supplier<T>) in Q48227496 and method ok(Runnable) in Q48227496 match".

Но просто изменив порядок методов

public class Q48227496 {
    public CompletableFuture<?> test() {
        return ok(() -> System.out.append("aaa"));
    }
    public <T> CompletableFuture<T> ok(T body) {
        return CompletableFuture.completedFuture(body);
    }
    public <T> CompletableFuture<T> ok(Supplier<T> action) {
        return CompletableFuture.supplyAsync(action);
    }
    public CompletableFuture<Void> ok(Runnable action) {
        return CompletableFuture.runAsync(action);
    }
}

заставляет компилятор принимать код без каких-либо ошибок.

Итак, очевидно, что это ошибка компилятора, так как порядок объявлений метода никогда не должен влиять на достоверность кода.

Кроме того, удаление метода ok(T) делает код принятым.

Обратите внимание, что всякий раз, когда компилятор принимает код, он считает ok(Supplier) более конкретным, чем ok(Runnable), что является ожидаемым поведением для параметра функции, который соответствует обоим.