Affects: 6.1.12

Hi all, I'm using spring-web in Kotlin as a REST client and I encountered some issues when trying to serialize a MutableList I prepared a sample code to show the issue:

fun main() {
    val client = RestTemplate(listOf(
        KotlinSerializationJsonHttpMessageConverter()
    ))
    val data = mutableListOf<String>()
    data.add("1")
    data.add("2")
    val entity = HttpEntity(data, HttpHeaders().apply {
        contentType = MediaType.APPLICATION_JSON
    })
    val response = client.exchange("https://httpbin.org/post", HttpMethod.POST, entity, String::class.java)
    logger.info(response.body)
}

But when I run this code, I get this error: No HttpMessageConverter for java.util.ArrayList and content type "application/json" I assumed KotlinSerializationJsonHttpMessageConverter Would be able to convert this to ["1", "2"], but it doesn't seem to work

Comment From: sdeleuze

That's due to the combination of a RestTemplate API limitation which, if I am not mistaken, does not allow to specify the request body type via a ParameterizedTypeReference and a https://github.com/Kotlin/kotlinx.serialization/ limitation with does not allow the serialization of ArrayList<*> (type erasure) with the default configuration.

On Spring side, to handle this use case I recommend switching from RestTemplate to RestClient API and do something like:

fun main(args: Array<String>) {
    val client = RestClient.builder().messageConverters {
        it.clear() // I will likely add the capability to provide directly a list of converters to avoid that inefficient default init + clear
        it.add(StringHttpMessageConverter())
        it.add(KotlinSerializationJsonHttpMessageConverter())
    }.build()
    val data = mutableListOf<String>()
    data.add("1")
    data.add("2")
    println(client.post().uri("https://httpbin.org/post")
        .bodyWithType<List<String>>(data).contentType(MediaType.APPLICATION_JSON)
        .retrieve().body<String>())
}

Alternatively if you really need to stay with RestTemplate, you can potentially customize the configuration of the KotlinSerializationJsonHttpMessageConverter with the Json parameter customizing the polymorphic serialization of ArrayList<*> (I have not tried but could be possible).

Comment From: sdeleuze

See #33536 for the improved message converters initialization.

Comment From: ChananM

Thanks @sdeleuze I eventually switched to Jackson which works much better with RestTemplate. As a side note, I don't think there's any issue with the kotlinx.serialization since using Json.encodeToString on the array works fine, even when serializing <*> type erasure. I also tried customizing KotlinSerializationJsonHttpMessageConverter by inheriting it and creating a custom converter that should work on any class and any content type, but unfortunately that also didn't work and I couldn't figure out why.

Comment From: sdeleuze

I am unsure as well, there may be some compile-time type parameter detection done by the Kotlin compiler in Json.encodeToString case that are not possible with the reflection based arrangement. I have asked a feedback to the Kotlin team and will let you know.

Comment From: sdeleuze

Feedback from Kotlin team

The reason that Json.encodeToString(data) works is that it is an inline function with reified parameter, and it uses typeOf() under the hood. typeOf<T>() is essentially a compiler intrinsic that is able to build a full KType for a given T.

That confirms we can't do better than current behavior for that use case.