Mockito: 如何在Java 8中匹配可变参数?

8

我正在将一个项目从Java 7迁移到8,并且遇到了一个Mockito "when" case的编译错误,我很难找到它的问题所在:

when(queryRunner.query(any(String.class), any(ResultSetHandler.class), anyVararg())).thenReturn(mockedWordResultList);

给我一个编译错误:

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

这个错误发生在1.8.0-b128版本构建中,但在1.7.0_45版本中未发生。我正在使用mockito 1.9.5。

在Java 8中正确使用anyVarArg()参数匹配的方法是什么?


我手头没有Java 8,所以无法轻松测试;但是如果将第三个参数强制转换为Object[]会发生什么? - Dawood ibn Kareem
2
我的问题是,如果你进行强制类型转换会怎样。换句话说,将(Object[])anyVararg()作为第三个参数传递。 - Dawood ibn Kareem
太棒了!你找出了bug并修复了。如果你想把它作为一个答案提交,我会点赞并接受。 - Paul Sanwald
是的,我想在回答之前再做更多的研究。显然,Java 8已经改变了它如何解析类型参数,Mockito可能需要进行相应的更改。最有可能的情况是,我们将会在Matchers中添加一个类似于public <T> T[] anyVarargOf(Class<T>)的方法。但是目前为止,我还不知道足够的信息来写出一个好的答案。 - Dawood ibn Kareem
谢谢你的提供。我会考虑一下的。很可能我要等到周末才能看这个。如果需要帮助,我会在这里联系你的。 - Dawood ibn Kareem
显示剩余2条评论
1个回答

7
问题在于类型推断已经得到了改进。anyVararg()是一个泛型方法,但您在嵌套的方法调用中使用它。在Java 8之前,类型推断的限制使得在将方法<T> T anyVararg()作为另一个方法调用的参数时,在不插入显式类型参数的情况下将其视为<Object> Object anyVararg()来处理。
因此,只有query(String, ResultSetHandler, Object...)被匹配为第三个参数被视为Object类型。
但现在,在Java 8中嵌套方法调用的类型推断可以工作了。对于<T> T anyVararg(),类型参数<T>可以是任何东西,包括ResultSetHandler。所以query(String,Object,ResultSetHandler)现在也是一个匹配的候选者。
由于现在有两种可能的匹配方式,通常方法选择的程序在这里适用。是的,这是模棱两可的。第一个参数相同,都是String,但对于另外两个参数,ResultSetHandlerObject更具体,但一个候选者接受第二个参数的更具体类型,而另一个接受第三个参数(和后续)的更具体类型。
显然,允许方法返回类型为任何东西的类型参数是不明确的,但类似Mockito的API中包含这样的方法是Java编程的一个特例。您将必须通过泛型方式强制执行类型Matchers.<Desired>anyVararg()或通过类型转换 (Desired)anyVararg()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接