I am getting a "reference to make is ambiguous" compiler error that I don't understand.
I have these two methods
public static <T> T make(String name, Class<T> parentClass,
boolean rethrowRuntimeExceptions,
Object... params) throws DLException
public static <T> T make(String name, Class<T> parentClass,
Object... params) throws DLException
This line of code is being marked as ambiguous
String className = "clsNme";
String one = "1";
String two = "2";
SimpleFactory.make(className, Object.class, false, one, two);
Here is the error
both method <T#1>make(String,Class<T#1>,boolean,Object...) in SimpleFactory and method <T#2>make(String,Class<T#2>,Object...) in SimpleFactory match
[javac] where T#1,T#2 are type-variables:
[javac] T#1 extends Object declared in method <T#1>make(String,Class<T#1>,boolean,Object...)
[javac] T#2 extends Object declared in method <T#2>make(String,Class<T#2>,Object...)
Doesn't the presence of the boolean parameter make the first method a closer match than the second?
If it matters, this is part of a PowerMock test Here is the complete method
public void makeCallsMakeWithFalse() throws Throwable {
Object expected = mock(Object.class);
String className = "clsNme";
String one = "1";
String two = "2";
spy(SimpleFactory.class);
doReturn(expected).when(SimpleFactory.class);
SimpleFactory.make(className, Object.class, false, one, two); // causes error
Object observed = SimpleFactory.make(className, Object.class, one, two); // doesn't cause error
assertEquals(expected, observed);
verifyStatic();
SimpleFactory.make(className, Object.class, false, one, two); // causes error
}
If it helps: I'm using javac 1.8.0_77, Mokito 1.10.19, and Powermock 1.6.3.
The compiler first tries to find a matching signature thst does not involve autoboxing/unboxing or variable arity invocation. Variable arity invocation is when you invoke a varargs method by passing a parameter list as the last argument (as opposed to an array).
In your case, both involve variable arity invocation. When this happens, the most specific overload is chosen. For your situation, neither is considered more specific as defined in the JLS. This is essentially because neither of the types boolean
and Object
is a subtype of the other.
Simplifying your example a bit, the following does not compile.
static void foo(boolean b, Object... arr) {
}
static void foo(Object... arr) {
}
public static void main(String[] args) {
foo(true);
}
The first version will not accept a single argument of type Object
and the second will not accept a single argument of type boolean
. Therefore neither is more specific. (Autoboxing only makes it look as if you can pass a boolean
as an argument of type Object
).
On the other hand, if you replace boolean
by Boolean
, it does compile because Boolean
is a subtype of Object
.
The problem lies in
Object... params
When calling SimpleFactory.make(className, Object.class, false, one, two);
Java will not know whether to box the "false" into a Boolean object and pass it as the first argument of the "params" varargs array (Boolean extends Object) and use
make(String name, Class<T> parentClass, Object... params)
or whether to call
make(String name, Class<T> parentClass, boolean rethrowRuntimeExceptions, Object... params)
since that signature can also accept a boolean before the params varargs.
Hence why it's ambiguous, both method signatures are applicable.
I think it is because the compiler doesn't know if you want the boolean parameter to be included in params or not. I could either call the function with 4 parameters and pass the boolean in as the 3rd parameter or it could call the function with 3 parameters and add the boolean to the Object... params. The compiler doesn't know what to do because of this ambiguity. Let me know if you need more information
Problem lies with
Object... params
To fix the ambiguity - change the code like below
To call
public static <T> T make(String name, Class<T> parentClass,
boolean rethrowRuntimeExceptions,
Object... params) throws DLException
call it like this:
SimpleFactory.make(className, Object.class, false, new Object[]{one, two});
And
To call
public static <T> T make(String name, Class<T> parentClass,
Object... params) throws DLException
call it like this:
SimpleFactory.make(className, Object.class, new Object[]{false,one, two});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With