I have a part of json response that could look lik...
# serialization
m
I have a part of json response that could look like this:
Copy code
{
  "properties": {
    "id": 1,
    "name": "Foo",
    "description": "FooFooFooFooFooFoo"
  }
}
or this:
Copy code
{
  "id": 290375,
  "properties": {
    "id": 3,
    "name": "Bar"
  }
}
So, to deserialize it, I've defined
Foo
&
Bar
models respectively that inherit from
FooBar
parent, and written a
JsonContentPolymorphicSerializer
to choose the deserialization strategy accordingly, and finally I've registered this serializer in the `Json`'s
SerializationModule
but that results in the following exception being thrown at runtime:
Copy code
Serializer for FooBar can't be registered as a subclass for polymorphic serialization because its kind SEALED is not concrete. To work with multiple hierarchies, register it as a base class.
java.lang.IllegalArgumentException: Serializer for FooBar can't be registered as a subclass for polymorphic serialization because its kind SEALED is not concrete. To work with multiple hierarchies, register it as a base class.
what does this message mean? & how to solve it, Any ideas? Code & small minimal reproducible test in the thread 🧵
Copy code
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import org.junit.Test

class FooBarSerializersTest {

    private val fooBarSerializersModule = SerializersModule {
        polymorphic(FooBar::class, baseSerializer = FooBarSerializer) {
            subclass(Foo::class)
            subclass(Bar::class)
        }
    }

    private val json = Json {
        serializersModule = fooBarSerializersModule
    }
    
    // Running this should fail!
    @Test
    fun deserializeToFooOrBar() {
        val foo = json.decodeFromString<Foo>("""
            {
                "properties": {
                    "id": 1,
                    "name": "Foo",
                    "description": "FooFooFooFooFooFoo"
                }
            }
        """.trimIndent())
        assert(foo == Foo(properties=FooBarProperties(id=1, name="Foo", description="FooFooFooFooFooFoo")))
        val bar = json.decodeFromString<Bar>("""
            {
                "id": 290375,
                "properties": {
                    "id": 3,
                    "name": "Bar"
                }
            }
        """.trimIndent())
        assert(bar == Bar(id=290375, properties=FooBarProperties(id=3, name="Bar", description=null)))
    }
}

object FooBarSerializer : JsonContentPolymorphicSerializer<FooBar>(FooBar::class) {
    override fun selectDeserializer(element: JsonElement): DeserializationStrategy<FooBar> {
        return when {
            "id" in element.jsonObject -> Bar.serializer()
            else -> Foo.serializer()
        }
    }
}

@Serializable
abstract class FooBar {
    abstract val properties: FooBarProperties
}

@Serializable
data class Foo(override val properties: FooBarProperties): FooBar()

@Serializable
data class Bar(val id: Long, override val properties: FooBarProperties): FooBar()

@Serializable
data class FooBarProperties(
    val id: Int,
    val name: String,
    val description: String? = null,
)