Skip to content

KotlinSerializationJsonHttpMessageConverter doesn't work on MutableList #33528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ChananM opened this issue Sep 12, 2024 · 5 comments
Closed
Assignees
Labels
status: declined A suggestion or change that we don't feel we should currently apply theme: kotlin An issue related to Kotlin support

Comments

@ChananM
Copy link

ChananM commented Sep 12, 2024

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

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 12, 2024
@sdeleuze sdeleuze self-assigned this Sep 12, 2024
@sdeleuze sdeleuze added the theme: kotlin An issue related to Kotlin support label Sep 12, 2024
@sdeleuze
Copy link
Contributor

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).

@sdeleuze sdeleuze closed this as not planned Won't fix, can't repro, duplicate, stale Sep 13, 2024
@sdeleuze sdeleuze added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 13, 2024
@sdeleuze
Copy link
Contributor

See #33536 for the improved message converters initialization.

@ChananM
Copy link
Author

ChananM commented Sep 13, 2024

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.

@sdeleuze
Copy link
Contributor

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.

@sdeleuze
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply theme: kotlin An issue related to Kotlin support
Projects
None yet
Development

No branches or pull requests

3 participants