JDK-7031404 : Reference is ambiguous with generics
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u24
  • Priority: P4
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: windows_7
  • CPU: x86
  • Submitted: 2011-03-26
  • Updated: 2017-07-07
  • Resolved: 2014-01-23
Description
FULL PRODUCT VERSION :
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7600]

A DESCRIPTION OF THE PROBLEM :
I'm having quite a tricky case here with generics and method overloading. Check out this example class:

public class Test {
    public <T> void setValue(Parameter<T> parameter, T value) {
    }

    public <T> void setValue(Parameter<T> parameter, Field<T> value) {
    }

    public void test() {
        // This works perfectly. <T> is bound to String
        // ambiguity between setValue(.., String) and setValue(.., Field)
        // is impossible as String and Field are incompatible
        Parameter<String> p1 = getP1();
        Field<String> f1 = getF1();
        setValue(p1, f1);

        // This causes issues. <T> is bound to Object
        // ambiguity between setValue(.., Object) and setValue(.., Field)
        // is possible as Object and Field are compatible
        Parameter<Object> p2 = getP2();
        Field<Object> f2 = getF2();
        setValue(p2, f2);
    }

    private Parameter<String> getP1() {...}
    private Parameter<Object> getP2() {...}

    private Field<String> getF1() {...}
    private Field<Object> getF2() {...}
}

The above example compiles perfectly in Eclipse (Java 1.6), but not with the Ant javac command (or with the JDK's javac command), where I get this sort of error message on the second invocation of setValue:

    reference to setValue is ambiguous, both method setValue(org.jooq.Parameter,T) in Test and method setValue(org.jooq.Parameter,org.jooq.Field) in Test match

According to the specification and to my understanding of how the Java compiler works, the most specific method should always be chosen: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448

In any case, even if <T> is bound to Object, which makes both setValue methods acceptable candidates for invocation, the one with the Field parameter always seems to be more specific. And it works in Eclipse, just not with the JDK's compiler.

Note: I discussed this issue on stackoverflow as well. I'm not entirely sure who's right:
http://stackoverflow.com/questions/5361513/reference-is-ambiguous-with-generics

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See description

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expected result: Compile class from description in Eclipse, works
ACTUAL -
Actual result: Compile class from description with javac, doesn't work

ERROR MESSAGES/STACK TRACES THAT OCCUR :
reference to setValue is ambiguous, both method setValue(org.jooq.Parameter,T) in Test and method setValue(org.jooq.Parameter,org.jooq.Field) in Test match

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Test {
    public <T> void setValue(Parameter<T> parameter, T value) {
    }

    public <T> void setValue(Parameter<T> parameter, Field<T> value) {
    }

    public void test() {
        // This works perfectly. <T> is bound to String
        // ambiguity between setValue(.., String) and setValue(.., Field)
        // is impossible as String and Field are incompatible
        Parameter<String> p1 = getP1();
        Field<String> f1 = getF1();
        setValue(p1, f1);

        // This causes issues. <T> is bound to Object
        // ambiguity between setValue(.., Object) and setValue(.., Field)
        // is possible as Object and Field are compatible
        Parameter<Object> p2 = getP2();
        Field<Object> f2 = getF2();
        setValue(p2, f2);
    }

    private Parameter<String> getP1() {...}
    private Parameter<Object> getP2() {...}

    private Field<String> getF1() {...}
    private Field<Object> getF2() {...}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Avoid method overloading in this case

Comments
Reduced test case: import java.util.List; class Test { <U> void m(List<U> l, U v) { } <V> void m(List<V> l1, List<V> l2) { } void test(List<Object> l) { m(l, l); //JDK 6/7 give ambiguity here - EJC compiles ok } } I think javac is correct in giving ambiguity error; both methods are applicable by subtyping (15.12.2.2); now which method is most specific? To answer this question we should try to do the following steps: 1) resolve <U> void m(List<U> l, U v) with arguments { List<V>, List<V> } - this gives U == V, which makes resolution fail, since List<V> is not subtype of [U:=V]U = V. 2) resolve <V> void m(List<V> l1, List<V> l2) with arguments { List<U>, U } - this gives V == U, which makes resolution fail, since U is not subtype of [V:=U]List<V> = List<U>. So, neither method is more specific; this should be an error, according to 15.12.2.5. Dan, can you confirm?
07-07-2017

Agree with Maurizio's evaluation. Not a bug.
23-01-2014