Osman Saral
03/22/2023, 5:41 PMval array = arrayOf(Json.encodeToString(obj))
val s = Json.encodeToString(array)
send(Frame.Text(s)) //send this string to the websocket.
I'm using KotlinxWebsocketSerializationConverter
and I want to do this absurd serialization automatically when call sendSerialized
of web socket session. Can I write a custom serializer to do this wrapping when I call it like sendSerialized(obj)
.
I know I can use KSerializer
and use @Serializable(with = ..
with it, but I don't want to mark every data class I create with it. Is this possible to do?
Can anyone lead me the way to do it?Adam S
03/22/2023, 9:24 PMfun FooKtorContext.sendOb(obj: MyDdpObj) = ...
Osman Saral
03/22/2023, 10:45 PMJohann Pardanaud
03/23/2023, 9:40 AMOsman Saral
03/24/2023, 6:38 AMserializerFromTypeInfo
which I want to use. I want to use the default behaviour before I wrap my object with array.
This also prevents me to use a custom serializer. I can't use the default serializer in my custom serializer when I use it with @Serializable(with = ..
Johann Pardanaud
03/24/2023, 10:59 AMobject NestedJsonSerializer : KSerializer<List<String>> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("some.NestedJsonSerializer", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: List<String>) = encoder.encodeString(Json.encodeToString(value))
override fun deserialize(decoder: Decoder): List<String> = Json.decodeFromString(decoder.decodeString())
}
@Serializable
data class SomePayload(
@Serializable(with = NestedJsonSerializer::class)
val strings: List<String>,
)
fun main() {
val payload = SomePayload(listOf("hello", "world"))
val encoded = Json.encodeToString(payload)
println(encoded)
val decoded = Json.decodeFromString<SomePayload>(encoded)
println(decoded)
}
Output:
{"strings":"[\"hello\",\"world\"]"}
SomePayload(strings=[hello, world])
Osman Saral
03/24/2023, 6:47 PMobject DDPMessageSerializer : KSerializer<Outgoing> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DDPMessageSerializer", PrimitiveKind.STRING)
private val json = Json {
encodeDefaults = true
ignoreUnknownKeys = true
}
override fun serialize(encoder: Encoder, value: Outgoing) {
val array = arrayOf(json.encodeToString(value)) //this one should use default serializer. not this KSerializer
val jsonString = json.encodeToString(array)
encoder.encodeString(jsonString)
}
override fun deserialize(decoder: Decoder): Outgoing = Json.decodeFromString(decoder.decodeString())
}
I'm using it like this:
@Serializable(with = DDPMessageSerializer::class)
sealed class Outgoing(val msg: String) {
@Serializable(with = DDPMessageSerializer::class) data class Connect(val session: String? = null, val version: String, val support: List<String>): Outgoing("connect")
}
webSocketSession?.sendSerialized(connectMessage)
This gives me StackOverflowError, cuz it always tries to serialize with this implementationJohann Pardanaud
03/25/2023, 9:12 AMOsman Saral
03/25/2023, 9:23 AMJohann Pardanaud
03/25/2023, 9:47 AMOsman Saral
03/27/2023, 9:44 AMMultiple sealed subclasses of 'class com.example.ddpclient.Outgoing' have the same serial name 'DDPMessageSerializer': 'class com.example.ddpclient.Outgoing$Connect', 'class com.example.ddpclient.Outgoing$Method'
@Serializable
sealed class Outgoing(val msg: String) {
@Serializable(with = DDPMessageSerializer::class) data class Connect(val session: String? = null, val version: String, val support: List<String>): Outgoing("connect")
@Serializable(with = DDPMessageSerializer::class) data class Method(val method: String, val params: List<@Contextual Any>, val id: String?): Outgoing("method")
}
Johann Pardanaud
03/27/2023, 10:10 AMOsman Saral
03/27/2023, 10:11 AMclass DDPMessageConverter(
private val json: Json,
): WebsocketContentConverter {
override suspend fun serializeNullable(
charset: Charset,
typeInfo: TypeInfo,
value: Any?
): Frame {
if (value !is Outgoing) return Frame.Text("")
val message = encodeToDDPMessage(value)
return Frame.Text(message)
}
override suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: Frame): Any? {
TODO("Not yet implemented")
}
override fun isApplicable(frame: Frame): Boolean {
return frame is Frame.Text
}
private fun encodeToDDPMessage(message: Outgoing): String {
val array = arrayOf(json.encodeToString(message))
return json.encodeToString(array)
}
}
Osman Saral
03/27/2023, 10:12 AM["{\"type\":\"com.example.ddpclient.Outgoing.Connect\",\"msg\":\"connect\",\"version\":\"1\",\"support\":[\"1\"]}"]