在scala varargs中强制单个参数

时间:2012-11-13 10:01:47

标签: scala mockito

给定一个带有两种方法的java类(取自mockito):

OngoingStubbing<T> thenReturn(T value);

OngoingStubbing<T> thenReturn(T value, T... values);

如果我使用

从scala调用
....thenReturn("something")

我收到错误:

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)

我无法弄清楚如何解决这个问题。

6 个答案:

答案 0 :(得分:21)

这是一个已知的Scala-Java互操作性问题,但遗憾的是它不在FAQ中。这是Scala ticket describing the problem。基本上,当您提供单个参数时,这两种方法都适用,并且Scala编译器当前没有任何启发式方法来决定哪一个是“更具体”的。 Alexey Romanov's approach to always use the varargs version是一个很好的解决方法:

thenReturn("something", Nil: _*)

还有question running into a similar problem with JCommander。其中一个答案给出了使用结构类型的巧妙解决方法。这种方法将在幕后使用反射,因此您可能想也可能不想走那个方向。对于您的用例,它看起来像:

type useSingleArgVersion = { def thenReturn(value: AnyRef): OngoingStubbing }
(...).asInstanceOf[useSingleArgVersion].thenReturn("something")

最后,有一个similar question running into a similar problem with mokito。它并没有真正提供任何变通方法,但如果您对发生这种情况的原因感兴趣,它确实会更详细地描述问题。

答案 1 :(得分:13)

这些答案都是错误的答案。差异很微妙,但这与linked ticket中的问题不同。那个确实要求不合理的体操称为非varargs方法。对于这个,以下就足够了。

thenReturn[String]("something")

或者,如果您由于某种原因不想这样做,则不需要类型别名和强制转换。您可以直接使用结构类型归属。

(this: { def thenReturn[T](s: T): OngoingStubbing[T] }).thenReturn("something")

这里的问题是在重载和多态的交集处的类型推断 - 一种方法更具体,但是scalac没有弄清楚哪种方法。由于重载和元组转换之间的相互作用,SI-2991中的问题是真正的模糊性 - 两者都不是更具体。

答案 2 :(得分:12)

如果可以接受调用vararg版本,

thenReturn("something", Nil: _*)

现在想不出没有varargs调用方法的方法。

答案 3 :(得分:1)

解决方法非常简单:

OngoingStubbing<T> thenReturn(T value);

OngoingStubbing<T> thenReturn(T value1, T valu2, T... values);

没有“varargs必须非空”功能。

答案 4 :(得分:1)

假设其他人在遇到overloaded method value thenReturn with alternatives错误时会发现此问题,我也想分享我的解决方案。

而不是

when(field.getValue(isA(classOf[Record]))).thenReturn(value)

我用

doReturn(value).when(field).getValue(isA(classOf[Record]))

解决了我案例中的歧义。

答案 5 :(得分:0)

我尝试了Steve的解决方案并遇到了一个巨大的编译器错误,包括:

scala.tools.nsc.symtab.Types$TypeError: type mismatch;
 found   : scala.reflect.Manifest[Nothing]
 required: scala.reflect.ClassManifest[B]
Note: Nothing <: B, but trait ClassManifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: B`. (SLS 3.2.10)

我能够使用以下内容:

thenReturn("something", Seq.empty[Object]: _*)