https://kotlinlang.org logo
#ktor
Title
# ktor
f

functionaldude

03/31/2022, 3:17 PM
Hi! I’m encountering a very strange behaviour when using the Ktor JS client with
JsonFeature
. I have the following class structure:
Copy code
@Serializable
sealed class Base {

  @Serializable
  class Child: Base()
}
When I do a post request with
Child()
as body, the class discriminator is missing (the body is just
{}
). I figured out that `Child`’s serializer is used, if I use `Base`’s serializer then the class discriminator is there:
Copy code
val payload = Base.Child()
  val payloadString1 = kotlinxSerializer.encodeToString(Base.serializer(), payload) // payloadString1 = "{"@class": "com.example.Base.Child"}"
  val payloadString2 = kotlinxSerializer.encodeToString(Base.Child.serializer(), payload) // payloadString2 = "{}"
The problem is, I can’t find a way to force the Ktor client to use the sealed class’s serializer. Is this a bug or the intended behaviour? And if this is the intended behaviour then how can I tell the Ktor client to use a different serializer?
a

Aleksei Tirman [JB]

03/31/2022, 4:10 PM
You can use the contextual serialization to force using the
Base
class serializer for
Child
objects. Here is an example:
Copy code
import io.ktor.client.HttpClient
import io.ktor.client.engine.apache.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
import io.ktor.client.request.*
import io.ktor.http.*
import kotlinx.serialization.modules.SerializersModule

suspend fun main() {
    val module = SerializersModule {
        contextual(Base.Child::class) {
            Base.serializer()
        }
    }

    val client = HttpClient(Apache) {
        install(JsonFeature) {
            serializer = KotlinxSerializer(kotlinx.serialization.json.Json {
                serializersModule = module
            })
        }
    }

    val r = <http://client.post|client.post><String>("<https://httpbin.org/post>") {
        body = Base.Child()
        contentType(ContentType.Application.Json)
    }
    println(r)
}

@kotlinx.serialization.Serializable
sealed class Base {

    @kotlinx.serialization.Serializable
    class Child: Base()
}
n

Nathan Kleinschmidt

04/05/2022, 10:40 PM
Where would you place the code that defines the
module
and
client
in a real project? Would it be in the same file as the
sealed class Base
? Seems like a lot of boilerplate to be in the main function.
3 Views