Summary

ServerResponse.BodyBuilder.bodyValueAndAwait API is broken when it is used with an application it uses for serialization the kotlinx.serialization library and the provided body uses generics. The library is unable to serialize the body since it is a type of Any and spring falls back to default one. This could lead to unexpected responses.

For example:

@Serializable
data class SomeBody(@SerialName("user_id") val userId: Int, val name: String)

suspend fun returnBody(request: ServerRequest): ServerResponse {
    return ServerResponse
        .ok()
        // Note: `fun ServerResponse.BodyBuilder.bodyValueAndAwait(body: Any)`
        // is not a reified function and is subject to type erasure.
        // In cases where response is a collection, the object is serialized as `Collection<Any>`,
        // and the response does not have the proper format, which is not expected.
        // Actual response: [{"userId":1,"name":"name"}]
        // Expected response : [{"user_id":1,"name":"name"}]
        .bodyValueAndAwait(listOf(SomeBody(1, "name")))
}

A minimum reproducible example can be found here.

Proposal

Make BodyBuilder.bodyValueAndAwait() a reified type of function. We can also migrate the API without breaking existing functionality.

Alternatives

Only document the behavior and accept it as the intended behavior.

Comment From: GeorgePap-719

Sorry for force-push while in-review. Minor changes in KDocs and error message.

Comment From: sdeleuze

After a deeper look, I am going to implement this feature differently on both Java and Kotlin side via #32713 which supersedes this issue.