summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodrigo Vedovato <vedovato.rodrigo@gmail.com>2022-10-13 12:19:03 -0300
committerGitHub <noreply@github.com>2022-10-13 18:19:03 +0300
commit0f35682bbcb41fa3adb24195658b892401f5f582 (patch)
tree518089183adc71fba359f81357f48ba5de364dd7
parentdc9983a608cac6215d2a3ebb8e41e8f710cab126 (diff)
downloadkotlinx.serialization-0f35682bbcb41fa3adb24195658b892401f5f582.tar.gz
Fix incorrect behavior while deserializing maps to sealed classes (#2052)
Fixes #2035
-rw-r--r--formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt25
-rw-r--r--formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt50
2 files changed, 75 insertions, 0 deletions
diff --git a/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt b/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt
index b65bb3df..22130f99 100644
--- a/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt
+++ b/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt
@@ -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)
}
@@ -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)
}
diff --git a/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt b/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt
new file mode 100644
index 00000000..52cd0384
--- /dev/null
+++ b/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt
@@ -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"])
+ }
+} \ No newline at end of file