Kotlin / kotlinx.serialization

Kotlin multiplatform / multi-format serialization
Apache License 2.0
5.39k stars 620 forks source link

Polymorphic Serialization fails with `Class 'ArrayList' is not registered for polymorphic serialization in the scope of 'Collection'` #1946

Open abhishiv opened 2 years ago

abhishiv commented 2 years ago

Describe the bug

Hey all, I have been stuck on this for hours. Apparently whenever I try to serialise a polymorphic type inside of a MutableList it fails with

Class 'ArrayList' is not registered for polymorphic serialization in the scope of 'Collection'.
[ERROR] Mark the base class as 'sealed' or register the serializer explicitly.

I just can't figure out the what a serializer for Arraylist in the scope of Collection would look like. I found #1341 but that doesn't look related since I'm trying to serialize an ArrayList of classes not primitives so that should be possible.

To Reproduce Attach a code snippet or test data if possible.

package test

import kotlinx.serialization.*
import kotlinx.serialization.json.*

@Serializable
sealed class Item2() {
    // code for eating, talking, walking
}

@Serializable
class Book2(val name: String) : Item2() {
}

@Serializable
class Magazine2(val name: String) : Item2() {
}

@Serializable
class Library2(val name: String ) {
    constructor() : this("Unnamed Library")

    @Polymorphic
    val items: MutableCollection<Item2> = mutableListOf()
}

class JSONSerde {

    companion object {
        val json = Json { ignoreUnknownKeys = true; prettyPrint = true; useArrayPolymorphism = true
         }
    }

    inline fun <reified T> serialize(data: T): String = json.encodeToString(data)

    inline fun <reified T> deserialize(string: String) = json.decodeFromString<T>(string)
}

fun main() {
    val library = Library2("My Library");
    library.items.add(Book2("Book 1"));
    library.items.add(Magazine2("Magazine 2"));
    val jsonSerde = JSONSerde()

    val string = jsonSerde.serialize(library)
    println(string)
}

Expected behavior

Environment

sandwwraith commented 2 years ago

Why do you need @Polymorphic on val items at all? Sealed classes should be polymorphic automatically.

abhishiv commented 2 years ago

Hey @sandwwraith If I remove the annotation on items, it still doesn't run and throws the same errror. I think it's because it's an ArrayList of a sealed class?

@Serializable
class Library2(val name: String ) {
    constructor() : this("Unnamed Library")

    val items: MutableCollection<Item2> = mutableListOf()
}
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:java (default-cli) on project functions-kotlin-hello-background: An exception occured while executing the Java class. null: InvocationTargetException: Class 'ArrayList' is not registered for polymorphic serialization in the scope of 'Collection'.
sandwwraith commented 2 years ago

It seems there's a confusion somewhere in the plugin that it doesn't recognize mutable collection. Try use MutableList instead

abhishiv commented 2 years ago

That works! Thanks a lot!

KotlinFactory commented 12 months ago

But it does not work if its immutable? Still? tf?