Type interference issue with the WebFlux WebTestClient and Kotlin

I’m building a prototype for a new application using Spring Webflux and Kotlin. Spring Webflux contains a WebTestClient for unit tests. According to the documentation I should be able to test the results of a REST call like this:

@Test
fun getVersion_SingleResult_ContentTypeJson_StatusCodeOk_ContentEqualsVersion() {
    //given
    val version = Version("Test", "1.0")
    val handler = ApiHandler(version)
    val client = WebTestClient.bindToRouterFunction(ApiRoutes(handler).apiRouter()).build()

    //expect
    val response = client.get().uri("/api/version/").exchange()
    response.expectStatus().isOk
    response.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
    response.expectBody(Version::class.java).isEqualTo(version)
}

However, I’m running into some type interference issues. The problem is in the combination of ‘expectBody’ and ‘isEqualTo’.

The error I get is:

Kotlin: Type inference failed: Not enough information to infer parameter T in fun isEqualTo(p0: Version!): T! Please specify it explicitly.
The used methods from the Spring Webflux framework have the following signatures:

<B> WebTestClient.BodySpec<B, ?> expectBody(Class<B> var1);

public interface BodySpec<B, S extends WebTestClient.BodySpec<B, S>> {
    <T extends S> T isEqualTo(B var1);
}

The code does compile when I call the isEqualTo method if I specify the function generic as <Nothing> (ie: isEqualTo<Nothing>(version), however this leads to a NullPointer exception even if the body of the response has a value.

I’m not sure how I could fix this. The combination of the wildcard in the expectBody and the circular generic in the BodySpec has me puzzled.

Well, got an update. Also asked it on Stack Overflow and a member of the Spring engineering team jumped in to explain that this is a known issue (See JIRA: Kotlin unable to inherit type for WebTestClient#BodySpec [SPR-15692] · Issue #20251 · spring-projects/spring-framework · GitHub)

Hi, I ran into the same issue.

Looks like the solution is to use an extension function .expectBody<Version>()

please refer to:
https://github.com/spring-projects/spring-framework/issues/20251#issuecomment-453457296

so, you can change your code to:

import org.springframework.test.web.reactive.server.expectBody
......
response<Version>.expectBody().isEqualTo(version)

it should work