I'm working on migrating a project from java 7 to 8, and have gotten a compilation error in a Mockito "when" case I'm having a hard time tracking down:
when(queryRunner.query(any(String.class), any(ResultSetHandler.class), anyVararg())).thenReturn(mockedWordResultList);
gives me a compilation error of:
java: reference to query is ambiguous both method
<T>query(java.lang.String,java.lang.Object,org.apache.commons.dbutils.ResultSetHandler<T>)
in org.apache.commons.dbutils.QueryRunner and method
<T>query(java.lang.String,org.apache.commons.dbutils.ResultSetHandler<T>,java.lang.Object...)
in org.apache.commons.dbutils.QueryRunner match
This error happens in build 1.8.0-b128, but doesn't happen in 1.7.0_45. I'm using mockito 1.9.5.
What's the correct way to use anyVarArg()
argument matching in java 8?
The problem is that the type inference has been improved. anyVararg()
is a generic method but you are using it in a nested method invocation. Before Java 8 the limitations of the type inference forced treating the method <T> T anyVararg()
like <Object> Object anyVararg()
when placed as an argument to another method invocation without inserting explicit type arguments.
So only query(String, ResultSetHandler, Object...)
matched as the third argument was treated as being of type Object
.
But now with Java 8 type inference works with nested method calls. Since for <T> T anyVararg()
the type parameter <T>
can be just anything, it can be ResultSetHandler
as well. So query(String,Object,ResultSetHandler)
also is a match candidate now.
(I omitted the type parameter <T>
from the outer call in both cases to make it less confusing)
Since we have two possible matches now, the normal procedure of method selection applies here. And yes, it’s ambiguous. The first parameter is the same, String
, but for the other two ResultSetHandler
is more specific than Object
but while one candidate accepts a more specific type for the second parameter, the other does for the third (and follow-ups).
It’s clear that type parameters that allow a method’s return type to be just anything are a source of ambiguity but APIs like Mockito’s containing such methods are a corner case of Java programming. You will have to force a type either the generic way Matchers.<Desired>anyVararg()
or via type cast (Desired)anyVararg()
.
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