Skip to content

Commit cfce5d8

Browse files
authored
Properties Format: Support sealed/polymorphic classes as class properties (#2255)
1 parent c01b19f commit cfce5d8

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public sealed class Properties(
5858
if (serializer is AbstractPolymorphicSerializer<*>) {
5959
val casted = serializer as AbstractPolymorphicSerializer<Any>
6060
val actualSerializer = casted.findPolymorphicSerializer(this, value as Any)
61+
encodeTaggedString(nested("type"), actualSerializer.descriptor.serialName)
6162

6263
return actualSerializer.serialize(this, value)
6364
}
@@ -102,9 +103,8 @@ public sealed class Properties(
102103
}
103104

104105
final override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
105-
val type = map["type"]?.toString()
106-
107106
if (deserializer is AbstractPolymorphicSerializer<*>) {
107+
val type = map[nested("type")]?.toString()
108108
val actualSerializer: DeserializationStrategy<Any> = deserializer.findPolymorphicSerializer(this, type)
109109

110110
@Suppress("UNCHECKED_CAST")

formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package kotlinx.serialization.properties
22

3+
import kotlin.reflect.KProperty1
34
import kotlinx.serialization.SerialName
45
import kotlinx.serialization.Serializable
56
import kotlin.test.Test
@@ -21,6 +22,9 @@ class SealedClassSerializationFromPropertiesTest {
2122
@Serializable
2223
data class SecondChild(override val firstProperty: Long, override val secondProperty: String) : BaseClass()
2324

25+
@Serializable
26+
data class CompositeClass(val item: BaseClass)
27+
2428
@Test
2529
fun testPropertiesDeserialization() {
2630
val props = mapOf(
@@ -44,7 +48,71 @@ class SealedClassSerializationFromPropertiesTest {
4448

4549
val instanceProperties = Properties.encodeToMap(instance)
4650

51+
assertEquals("FIRSTCHILD", instanceProperties["type"])
4752
assertEquals(1L, instanceProperties["firstProperty"])
4853
assertEquals("one", instanceProperties["secondProperty"])
4954
}
55+
56+
@Test
57+
fun testWrappedPropertiesDeserialization() {
58+
val props = mapOf(
59+
"0.type" to "FIRSTCHILD",
60+
"0.firstProperty" to 1L,
61+
"0.secondProperty" to "one",
62+
"1.type" to "SECONDCHILD",
63+
"1.firstProperty" to 2L,
64+
"1.secondProperty" to "two"
65+
)
66+
67+
val instances: List<BaseClass> = Properties.decodeFromMap(props)
68+
69+
val expected = listOf(FirstChild(1, "one"), SecondChild(2, "two"))
70+
assertEquals(expected, instances)
71+
}
72+
73+
@Test
74+
fun testWrappedPropertiesSerialization() {
75+
val instances: List<BaseClass> = listOf(
76+
FirstChild(firstProperty = 1L, secondProperty = "one"),
77+
SecondChild(firstProperty = 2L, secondProperty = "two")
78+
)
79+
80+
val instanceProperties = Properties.encodeToMap(instances)
81+
82+
assertEquals("FIRSTCHILD", instanceProperties["0.type"])
83+
assertEquals(1L, instanceProperties["0.firstProperty"])
84+
assertEquals("one", instanceProperties["0.secondProperty"])
85+
assertEquals("SECONDCHILD", instanceProperties["1.type"])
86+
assertEquals(2L, instanceProperties["1.firstProperty"])
87+
assertEquals("two", instanceProperties["1.secondProperty"])
88+
}
89+
90+
@Test
91+
fun testCompositeClassPropertiesDeserialization() {
92+
val props = mapOf(
93+
"item.type" to "SECONDCHILD",
94+
"item.firstProperty" to 7L,
95+
"item.secondProperty" to "nothing"
96+
)
97+
98+
val composite: CompositeClass = Properties.decodeFromMap(props)
99+
100+
assertEquals(CompositeClass(SecondChild(7L, "nothing")), composite)
101+
}
102+
103+
@Test
104+
fun testCompositeClassPropertiesSerialization() {
105+
val composite = CompositeClass(
106+
item = FirstChild(
107+
firstProperty = 5L,
108+
secondProperty = "something"
109+
)
110+
)
111+
112+
val compositeProperties = Properties.encodeToMap(composite)
113+
114+
assertEquals("FIRSTCHILD", compositeProperties["item.type"])
115+
assertEquals(5L, compositeProperties["item.firstProperty"])
116+
assertEquals("something", compositeProperties["item.secondProperty"])
117+
}
50118
}

0 commit comments

Comments
 (0)