I’m trying to implement a general serialization framework to convert outgoing and incoming messages to json using the kotlinx serialialization. I’m developing a multiplatform app, so I’m trying to get it to run on KotlinJVM and KotlinJS.
For this, I add a type
field to every message and use a map that maps each type
string to a KClass
. What’s the type for that map? It contains KClass<>
objects whose classes extend the Message class, therefore in java I’d specify my map as
Map<KClass<? extends Message>, String>
.
How can I do that in Kotlin?
Afterwards I need to serialize and deserialize the message based on its key and therefore type. Java frameworks take a Class parameter for the type of the object I want to deserialize/instantiate (e.g. gson.fromJson(ClientMessage.class)
). In Kotlin this is done using reified
parameters Json.decodeFromString<Type>
. I do not know the type of the message at compile time though and just have a reference to a KClass
, how can I instantiate an object based on that?
@Serializable
open class Message(val type: String) {
companion object {
val messageTypes: Map<KClass<out Message>, String> = mapOf(
ClientLoginMessage::class to "clientLoginMessage",
Message::class to "message"
)
inline fun <reified T> getMessageTypeByClass(): String = messageTypes[T::class]!! // utility for defining the type in the constructors of the individual messages
}
fun toJson() = Json.encodeToString(this)
fun fromJson(json: String): Message? {
val plainMessage = Json.decodeFromString<Message>(json) // get type string from json
return messageTypes.entries.find { it.value == plainMessage.type }?.let {
// how can I use the KClass from it.key as reified parameter?
Json.decodeFromString<?????>(json)
}
}
}
@Serializable
class ClientLoginMessage
: Message(Message.getMessageTypeByClass<ClientLoginMessage>()) {}