probably asked a few times now but somehow can't f...
# serialization
m
probably asked a few times now but somehow can't find the answer that fix my problem 😅. got
kotlinx.serialization.json.internal.JsonDecodingException: Polymorphic serializer was not found for missing class discriminator ('null')
when trying to decode json to data class with a generic. code in thread 🧵
Copy code
interface Attribute

@Serializable
data class NameAttribute(val name: String) : Attribute

@Serializable
data class StuffAttribute(val stuff: Int) : Attribute

@Serializable
data class SomeData<A : Attribute>(
    val id: String,
    val type: String,
    val attribute: A
)
test:
Copy code
private val json = Json {
    ignoreUnknownKeys = true
    isLenient = true
    serializersModule = SerializersModule {
        polymorphic(Attribute::class) {
            subclass(NameAttribute::class)
            subclass(StuffAttribute::class)
        }
    }
}

@Test
fun testAttributeDeserialize() {
    val response = """
        {
            "id": "some id",
            "type": "name",
            "attribute": {
                "name": "name here"
            }
        }
    """.trimIndent()

    val result = json.decodeFromString<SomeData<Attribute>>(response)

    assertEquals("some id", result.id)
    assertEquals("name here", (result.attribute as NameAttribute).name)

    val stuffResponse = """
        {
            "id": "stuff id",
            "type": "stuff",
            "attribute": {
                "stuff": 1
            }
        }
    """.trimIndent()

    val stuffResult = json.decodeFromString<SomeData<Attribute>>(stuffResponse)

    assertEquals("stuff id", stuffResult.id)
    assertEquals(1, (stuffResult.attribute as StuffAttribute).stuff)
}
am I missing something obvious here?
a
If you are working with manual raw json, you need to add in the class discriminator to your attribute object (default key for it is
type
) Json for the
SomeData
with a
StuffAttribute
should look like this:
Copy code
{
  "id": "stuff id",
  "type": "stuff",
  "attribute": {
    "type": "<package>.StuffAttribute",
    "stuff": 1
  }
}
Can also add
@SerialName("name" / "stuff")
to the respective classes to avoid writing out the fully qualified name
Oh, didn't notice it at first but the type parameter you're using for decoding
SomeData
is just a generic
Attribute
You can just change:
val stuffResult = json.decodeFromString<SomeData<Attribute>>(stuffResponse)
to
val stuffResult = json.decodeFromString<SomeData<StuffAttribute>>(stuffResponse)