Spring Boot升级2.6.4后测试用例allSatisfy重载解析歧义报错
Spring Boot升级后AssertJ的allSatisfy方法编译报错问题
问题背景
将Spring Boot从2.1.7版本升级至2.6.4版本后,原有可正常运行的测试用例出现Kotlin编译错误,对应测试代码如下:
@Test fun `Should include id in all outbound requests`() { (authenticationSource as TestAuthenticationSource).setCoordinatorToken() val request = PersonSearch().apply { firstName = "Xyz" lastName = "Abc" } val oid = UUID.randomUUID().toString() client .post() .uri("/v/search/outbound") .headers { it.setBearerAuth("fakeToken") it.set(CORRELATION_ID, oid) } .body(Mono.just(request), PersonSearch::class.java) .exchange() assertThat(server.requestCount).isEqualTo(2) // 下行代码在旧版本可正常运行,升级后报错 assertThat(server.takeAllRequests()).allSatisfy { assertThat(it.headers.toMultimap()).containsEntry(CORRELATION_ID, listOf(oid)) } // 尝试显式声明lambda参数it的写法仍报错 assertThat(server.takeAllRequests()).allSatisfy { it -> assertThat(it.headers.toMultimap()).containsEntry(CORRELATION_ID, listOf(oid)) } }
报错信息
编译时提示重载解析歧义,核心报错内容如下:
Overload resolution ambiguity. All these functions match. public open fun allSatisfy(requirements: Consumer<in RecordedRequest!>!): ObjectArrayAssert<RecordedRequest!>! defined in org.assertj.core.api.ObjectArrayAssert public open fun allSatisfy(requirements: ThrowingConsumer<in RecordedRequest!>!): ObjectArrayAssert<RecordedRequest!>! defined in org.assertj.core.api.ObjectArrayAssert
Kotlin编译器抛出的完整异常与上述信息一致:
Kotlin: Overload resolution ambiguity: public open fun allSatisfy(p0: Consumer<in RecordedRequest!>!): ObjectArrayAssert<RecordedRequest!>! defined in org.assertj.core.api.ObjectArrayAssert public open fun allSatisfy(p0: ThrowingConsumer<in RecordedRequest!>!): ObjectArrayAssert<RecordedRequest!>! defined in org.assertj.core.api.ObjectArrayAssert
根因分析
Spring Boot 2.6.x版本内置的AssertJ版本更高,新版AssertJ为allSatisfy方法新增了入参类型为ThrowingConsumer的重载。Kotlin的SAM转换机制同时支持普通Consumer接口和允许抛出受检异常的ThrowingConsumer接口,直接传入lambda表达式时,编译器无法判定应该将lambda转换为哪一个接口实例,因此抛出重载歧义错误。
修复方案
直接显式指定lambda对应的接口类型即可消除歧义,运行逻辑和旧版本完全一致,修复代码示例:
import java.util.function.Consumer // 其余代码不变,仅修改allSatisfy入参部分 assertThat(server.takeAllRequests()).allSatisfy(Consumer { assertThat(it.headers.toMultimap()).containsEntry(CORRELATION_ID, listOf(oid)) })
如果项目中大量使用该方法,也可以封装AssertJ的Kotlin扩展函数统一处理,避免每次写代码都显式声明Consumer类型。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

