Kotlin / kotlinx.serialization

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

SealedClassSerializer doesn't handle value classes correctly #2839

Closed valeriyo closed 1 week ago

valeriyo commented 3 weeks ago

Describe the bug SealedClassSerializer doesn't serialize value subclasses into the expected structure, with type property. Instead it just dumps the raw value, which won't deserialize back!

To Reproduce See test below

Expected behavior Instead of raw value, the resulting JSON should be of the same structure, as regular subclasses: "{\"type\":\".......\",\"value\":......}"

Environment

@Serializable sealed interface Sealed {

@Serializable @SerialName("DataObject") data object DataObject : Sealed

@Serializable @SerialName("DataClass") data class DataClass(val code: Int) : Sealed

@Serializable @SerialName("ValueClass") @JvmInline value class ValueClass(val code: Int) : Sealed }

class SealedTest {

@Test fun test() { val serializer = Sealed.serializer()

assertEquals(
  expected = "{\"type\":\"DataObject\"}",
  actual = Json.encodeToString(serializer, Sealed.DataObject),
)

assertEquals(
  expected = "{\"type\":\"DataClass\",\"code\":111}",
  actual = Json.encodeToString(serializer, Sealed.DataClass(111)),
)

assertEquals(
  expected = "222", // WRONG! should be "{\"type\":\"DataClass\",\"value\":222}"
  actual = Json.encodeToString(serializer, Sealed.ValueClass(222)),
)

} }

sandwwraith commented 1 week ago

This is caused by the fact that your ValueClass is an inline class over Int. There is simply nowhere to add type, because Int is not an object. See https://github.com/Kotlin/kotlinx.serialization/issues/2049#issuecomment-1476647228