Given a java class with two methods (taken from mockito):
OngoingStubbing<T> thenReturn(T value);
OngoingStubbing<T> thenReturn(T value, T... values);
If I invoke from scala with
....thenReturn("something")
I get an error:
Description Resource Path Location Type
ambiguous reference to overloaded definition, both method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object, x$2: <repeated...>[java.lang.Object])org.mockito.stubbing.OngoingStubbing[java.lang.Object] and method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object] match argument types (java.lang.String)
And I cannot figure out how to fix this.
This is a known Scala-Java interoperability problem, though it's unfortunately not in the FAQ. Here's the Scala ticket describing the problem. Essentially, both methods are applicable when you give a single argument, and the Scala compiler currently doesn't have any heuristic to decide which one is "more specific". Alexey Romanov's approach to always use the varargs version is a good workaround:
thenReturn("something", Nil: _*)
There is also a question running into a similar problem with JCommander. One of the answers there gives a clever workaround using structural types. This approach will use reflection behind the scenes, so you may or may not want to go that direction. For your use case, it would look something like:
type useSingleArgVersion = { def thenReturn(value: AnyRef): OngoingStubbing }
(...).asInstanceOf[useSingleArgVersion].thenReturn("something")
Finally, there is a similar question running into a similar problem with mokito. It doesn't really provide any workarounds, but it does describe the problem in a bit more detail, if you're interested in the reason this happens.
If calling the vararg version is acceptable,
thenReturn("something", Nil: _*)
Can't think of a way to call the method without varargs right now.
These answers are all to the wrong question. The difference is subtle, but this is not the same issue as the one in the linked ticket. That one does require unreasonable gymnastics to call the non-varargs method. For this one, the following is enough.
thenReturn[String]("something")
Or, if you didn't want to do that for some reason, you don't need the type alias and the cast. You can use a structural type ascription directly.
(this: { def thenReturn[T](s: T): OngoingStubbing[T] }).thenReturn("something")
The issue here is type inference at the intersection of overloading and polymorphism - one method is more specific, but scalac doesn't figure out which. The issue in SI-2991 is genuine ambiguity due to an interaction between overloading and tuple conversion - neither is more specific.
Assuming others will find this question when having the overloaded method value thenReturn with alternatives
error, I want to share my solution as well.
Instead of
when(field.getValue(isA(classOf[Record]))).thenReturn(value)
I use
doReturn(value).when(field).getValue(isA(classOf[Record]))
which resolves the disambiguity in my case.
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