jsonkotlinjson-deserializationkotlin-nativekotlinx.serialization

Polymorphic deserialization with kotlinx.serialization in Kotlin/Native


I want to decode a json string containing a list of objects in a polymorphic class structure using kotlinx.serialization in a Kotlin Multiplatform project, but it works only on JVM, not on Native. Here is a minimum reproducible example:

@Serializable
abstract class Project {
    abstract val name: String
}

@Serializable
@SerialName("BasicProject")
data class BasicProject(override val name: String): Project()

@Serializable
@SerialName("OwnedProject")
data class OwnedProject(override val name: String, val owner: String) : Project()

fun main() {
    val data = Json.decodeFromString<List<Project>>("""
        [
            {"type":"BasicProject","name":"example"},
            {"type":"OwnedProject","name":"kotlinx.serialization","owner":"kotlin"} 
        ]
    """))
}  

This works on JVM but throws the following exception on Native:

kotlinx.serialization.SerializationException: Serializer for class ‘Project’ is not found.
Mark the class as @Serializable or provide the serializer explicitly.
On Kotlin/Native explicitly declared serializer should be used for interfaces and enums without @Serializable annotation.message

This problem has been discussed before in the context of encoding and some workarounds have been suggested, e.g. here, but my problem is decoding. Is there a workaround, or do I simply have to implement my own json parser?


Solution

  • You need to explicitly pass respectful serializer and serializersModule:

    object ListOfProjectSerializer : KSerializer<List<Project>> by ListSerializer(Project.serializer())
    
    val module = SerializersModule {
        polymorphic(Project::class) {
            subclass(BasicProject::class)
            subclass(OwnedProject::class)
        }
    }
    
    fun main() {
        val data = Json { serializersModule = module }.decodeFromString(
            ListOfProjectSerializer,
            """
            [
                {"type":"BasicProject","name":"example"},
                {"type":"OwnedProject","name":"kotlinx.serialization","owner":"kotlin"} 
            ]
            """
        )
    }