Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-15692

Kotlin unable to inherit type for WebTestClient#BodySpec


    • Type: Improvement
    • Status: Closed
    • Priority: Minor
    • Resolution: Complete
    • Affects Version/s: 5.0 RC2
    • Fix Version/s: 5.0.6, 5.1 RC1
    • Component/s: Test, Web
    • Labels:


      It seems that due to recursive generics in BodySpec interface

      interface BodySpec<B, S extends BodySpec<B, S>>

      and due to expectBody method returns

      <B> BodySpec<B, ?> expectBody(Class<B> bodyType);

      WebTestClient cannot be used in Kotlin.

      Kotlin inherits the result of .expectBody(Person::class.java) as BodySpec<Person, *> and thus the following methods in chain cannot be constructed due to the following error:

      Error:(25, 20) Kotlin: Type inference failed: Not enough information to infer parameter T in fun <T : Nothing!> isEqualTo(p0: Controller.Person!): T!
      Please specify it explicitly.

      And it applies only Nothing as a type parameter.
      But in this case generated bytecode contains the following line

      throw null


          fun `test get`() {
              val expectBody: BodySpec<Person, *> = client.get().uri("/person/42").exchange()
              expectBody.isEqualTo(Person("42", "Ivan"))                            // doesn't compile here
              expectBody.isEqualTo<BodySpec<Person, *>>(Person("42", "Ivan"))       // doesn't compile here
              expectBody.isEqualTo<Nothing>(Person("42", "Ivan"))                   // compile but lead to "throw null" in bytecode

      If you work with list the situation is a bit better - Kotlin still cannot inherit type param automatically but you can specify it explicitly due to method expectBodyList in interface ListBodySpec doesn't return wildcards

      <E> ListBodySpec<E> expectBodyList(Class<E> elementType);


          fun `test list`() {
              val expectBodyList: ListBodySpec<Person> = client.get().uri("/person").exchange()
              expectBodyList.consumeWith<ListBodySpec<Person>> { list -> Assert.assertTrue(true) }   // need to specify type param explicitly

      Full example with java and kotlin can be found here.
      Tests in java works well in these cases.


          Issue Links



              • Assignee:
                sdeleuze Sébastien Deleuze
                mskonovalov Mikhail Konovalov
                Last updater:
                Stéphane Nicoll
              • Votes:
                0 Vote for this issue
                5 Start watching this issue


                • Created:
                  Days since last comment:
                  34 weeks, 5 days ago