Kotlin serialization is hard! How do I do get Kotlin to believe that the values in my properties map are either primitives or classes annotated with @Serializable
?
I'm trying to turn a class like this: class Entity(val id: String, val type: String, val properties: Map<String, *>)
where I know that *
is primitive or @Serializable
or String
into JSON, e.g.: { id: "0", type: "falcon", max-flight-range-nm: 10 }
import kotlinx.serialization.*
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.encodeToJsonElement
fun main() {
val json = Json {
prettyPrint = true
}
val falcon = Entity("0", "falcon", mapOf("max-flight-range-nm" to 10))
println(json.encodeToString(falcon))
// Desired JSON (no nesting of 'Entity.parameters', they bump-up into parent intentionally
// { id: "0", type: "falcon", max-flight-range-nm: 10 }
// Avoiding extra nesting is conceptually similar to Jackson's @JsonAnyGetter annotation: https://www.baeldung.com/jackson-annotations#1-jsonanygetter
}
@Serializable
class Entity(val id: String, val type: String, @Contextual val properties: Map<String, *>) {
@Serializer(forClass = Entity::class)
companion object : KSerializer<Entity> {
override fun serialize(encoder: Encoder, value: Entity) {
encoder.encodeString(value.id)
encoder.encodeString(value.type)
// attempted hack to encode properties at this level
for ((mapKey, mapValue) in value.properties) {
val valueJson = Json.encodeToJsonElement(mapValue)
val jsonObject = JsonObject(mapOf(mapKey to valueJson))
encoder.encodeString(jsonObject.toString())
}
}
}
}
I have full control over all code, so if needed I could go so far as to write a bunch of sealed class PropertyValue
subclasses and mark them as @Serializable
- so IntPropertyValue
, StringPropertyValue
, FooPropertyValue
, etc. Maybe that's the only way?
Unfortunately the above fails at compile-time (no errors in Intelli-J though):
org.jetbrains.kotlin.codegen.CompilationException: Back-end (JVM) Internal error: Serializer for element of type Any? has not been found.