kotlinx.serialization icon indicating copy to clipboard operation
kotlinx.serialization copied to clipboard

Incorrect deserialization of sealed class

Open pablobaldez opened this issue 3 years ago • 1 comments

Describe the bug I'm using the kotlin serialization properties (not the json) and I'm getting MissingFieldException error when I try to decode a sealed class from a map To Reproduce I have a map

// my sealed classes 
@Serializable
@Keep
sealed class Odds {
    abstract val value: Long
}

@SerialName("EUROPEAN")
@Serializable
@Keep
data class European(override val value: Long) : Odds()

@SerialName("AMERICAN")
@Serializable
@Keep
data class American(override val value: Long) : Odds()


val map = mapOf("type" to "AMERICAN", "value" to 1)
val odds: Odds = Properties.decodeFromMap(map)

This is the stracktrace I have

Caused by: kotlinx.serialization.MissingFieldException: Field 'value' is required for type with serial name 'AMERICAN', but it was missing
                                                                                         	at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
                                                                                         	at br.com.mob1st.bet.features.competitions.domain.American.<init>(Bet.kt:36)
                                                                                         	at br.com.mob1st.bet.features.competitions.domain.American$$serializer.deserialize(Bet.kt:36)
                                                                                         	at br.com.mob1st.bet.features.competitions.domain.American$$serializer.deserialize(Bet.kt:36)
                                                                                         	at kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
                                                                                         	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:178)
                                                                                         	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:207)
                                                                                         	at kotlinx.serialization.internal.TaggedDecoder$decodeSerializableElement$1.invoke(Tagged.kt:280)
                                                                                         	at kotlinx.serialization.internal.TaggedDecoder.tagBlock(Tagged.kt:297)
                                                                                         	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableElement(Tagged.kt:280)
                                                                                         	at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:533)
                                                                                         	at kotlinx.serialization.internal.AbstractPolymorphicSerializer.deserialize(AbstractPolymorphicSerializer.kt:57)
                                                                                         	at kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
                                                                                         	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:178)
                                                                                         	at kotlinx.serialization.properties.Properties.decodeFromMap(Properties.kt:173)
                                                                                         	at br.com.mob1st.bet.features.competitions.data.ContestMapperKt$nodeBuilder$1.invoke(ContestMapper.kt:226)
                                                                                         	at br.com.mob1st.bet.features.competitions.data.ContestMapperKt$nodeBuilder$1.invoke(ContestMapper.kt:33)
                                                                                         	at br.com.mob1st.bet.features.competitions.data.CompetitionCollection.getConfrontationsById(CompetitionCollection.kt:54)
                                                                                         	at br.com.mob1st.bet.features.competitions.data.CompetitionCollection$getConfrontationsById$1.invokeSuspend(Unknown Source:12)
                                                                                         	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) 
                                                                                         	at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:33) 
                                                                                         	at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102) 
                                                                                         	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) 
                                                                                         	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) 
                                                                                         	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42) 
                                                                                         	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95) 
                                                                                         	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570) 
                                                                                         	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) 
                                                                                         	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677) 
                                                                                         	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664) 

Expected behavior The deserialization should run properly Environment

  • Kotlin version: 1.7.0
  • Library version: 1.4.0
  • Kotlin platforms: Android
  • Gradle version: gradle-7.4
  • IDE version Android Studio dolphin
  • Other relevant context [e.g. OS version, JRE version, ... ]: I tried to debug the the lib code to figure out where are the cause of the problem, and it seems that for some reason the NamedValueDecoder are return value.value in the getTag method

pablobaldez avatar Sep 14 '22 18:09 pablobaldez

important info: If I try the same thing using the kotlinx-serialization-json it works perfectly

val oddsMap = mapOf(
    "type" to JsonPrimitive("AMERICAN"),
    "value" to JsonPrimitive(1L)
)
val e = JsonObject(
    oddsMap
)
val odds: Odds = Json {
    ignoreUnknownKeys = true
}.decodeFromJsonElement(e)

pablobaldez avatar Sep 14 '22 18:09 pablobaldez