Skip to content

Commit

Permalink
Fix incorrect behavior while deserializing maps to sealed classes (#2052
Browse files Browse the repository at this point in the history
)

Fixes #2035
  • Loading branch information
rodrigovedovato committed Oct 13, 2022
1 parent dc9983a commit 0f35682
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
Expand Up @@ -53,6 +53,18 @@ public sealed class Properties(

protected abstract fun encode(value: Any): Value

@Suppress("UNCHECKED_CAST")
final override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
if (serializer is AbstractPolymorphicSerializer<*>) {
val casted = serializer as AbstractPolymorphicSerializer<Any>
val actualSerializer = casted.findPolymorphicSerializer(this, value as Any)

return actualSerializer.serialize(this, value)
}

return serializer.serialize(this, value)
}

override fun encodeTaggedValue(tag: String, value: Any) {
map[tag] = encode(value)
}
Expand Down Expand Up @@ -89,6 +101,19 @@ public sealed class Properties(
return structure(descriptor).also { copyTagsTo(it) }
}

final override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
val type = map["type"]?.toString()

if (deserializer is AbstractPolymorphicSerializer<*>) {
val actualSerializer: DeserializationStrategy<out Any> = deserializer.findPolymorphicSerializer(this, type)

@Suppress("UNCHECKED_CAST")
return actualSerializer.deserialize(this) as T
}

return deserializer.deserialize(this)
}

final override fun decodeTaggedValue(tag: String): Value {
return map.getValue(tag)
}
Expand Down
@@ -0,0 +1,50 @@
package kotlinx.serialization.properties

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs

class SealedClassSerializationFromPropertiesTest {
@Serializable
sealed class BaseClass {
abstract val firstProperty: Long
abstract val secondProperty: String
}

@SerialName("FIRSTCHILD")
@Serializable
data class FirstChild(override val firstProperty: Long, override val secondProperty: String) : BaseClass()

@SerialName("SECONDCHILD")
@Serializable
data class SecondChild(override val firstProperty: Long, override val secondProperty: String) : BaseClass()

@Test
fun testPropertiesDeserialization() {
val props = mapOf(
"type" to "FIRSTCHILD",
"firstProperty" to 1L,
"secondProperty" to "one"
)

val instance: BaseClass = Properties.decodeFromMap(props)

assertIs<FirstChild>(instance)
assertEquals(instance.firstProperty, 1)
assertEquals(instance.secondProperty, "one")
}

@Test
fun testPropertiesSerialization() {
val instance: BaseClass = FirstChild(
firstProperty = 1L, secondProperty = "one"
)

val instanceProperties = Properties.encodeToMap(instance)

assertEquals(1L, instanceProperties["firstProperty"])
assertEquals("one", instanceProperties["secondProperty"])
}
}

0 comments on commit 0f35682

Please sign in to comment.