diff --git a/README.md b/README.md index f554b457eb..f254e2f77b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) [![TeamCity build](https://img.shields.io/teamcity/http/teamcity.jetbrains.com/s/KotlinTools_KotlinxSerialization_Ko.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=KotlinTools_KotlinxSerialization_Ko&guest=1) [![Kotlin](https://img.shields.io/badge/kotlin-1.8.10-blue.svg?logo=kotlin)](http://kotlinlang.org) -[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-serialization-core/1.5.0)](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-serialization-core/1.5.0/pom) +[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-serialization-core/1.5.0)](https://central.sonatype.com/artifact/org.jetbrains.kotlinx/kotlinx-serialization-core/1.5.0) [![KDoc link](https://img.shields.io/badge/API_reference-KDoc-blue)](https://kotlinlang.org/api/kotlinx.serialization/) [![Slack channel](https://img.shields.io/badge/chat-slack-blue.svg?logo=slack)](https://kotlinlang.slack.com/messages/serialization/) diff --git a/docs/serializers.md b/docs/serializers.md index 0059a0151a..2da17fa43a 100644 --- a/docs/serializers.md +++ b/docs/serializers.md @@ -814,7 +814,7 @@ fun main() { ### Specifying serializer globally using typealias kotlinx.serialization tends to be the always-explicit framework when it comes to serialization strategies: normally, -they should be explicitly mentioned in `@Serialiazble` annotation. Therefore, we do not provide any kind of global serializer +they should be explicitly mentioned in `@Serializable` annotation. Therefore, we do not provide any kind of global serializer configuration (except for [context serializer](#contextual-serialization) mentioned later). However, in projects with a large number of files and classes, it may be too cumbersome to specify `@file:UseSerializers` diff --git a/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt b/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt index 4fa55d299b..8760950c3c 100644 --- a/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt +++ b/formats/properties/commonMain/src/kotlinx/serialization/properties/Properties.kt @@ -58,6 +58,7 @@ public sealed class Properties( if (serializer is AbstractPolymorphicSerializer<*>) { val casted = serializer as AbstractPolymorphicSerializer val actualSerializer = casted.findPolymorphicSerializer(this, value as Any) + encodeTaggedString(nested("type"), actualSerializer.descriptor.serialName) return actualSerializer.serialize(this, value) } @@ -102,9 +103,8 @@ public sealed class Properties( } final override fun decodeSerializableValue(deserializer: DeserializationStrategy): T { - val type = map["type"]?.toString() - if (deserializer is AbstractPolymorphicSerializer<*>) { + val type = map[nested("type")]?.toString() val actualSerializer: DeserializationStrategy = deserializer.findPolymorphicSerializer(this, type) @Suppress("UNCHECKED_CAST") diff --git a/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt b/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt index 52cd03847f..f933232475 100644 --- a/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt +++ b/formats/properties/commonTest/src/kotlinx/serialization/properties/SealedClassSerializationFromPropertiesTest.kt @@ -1,5 +1,6 @@ package kotlinx.serialization.properties +import kotlin.reflect.KProperty1 import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlin.test.Test @@ -21,6 +22,9 @@ class SealedClassSerializationFromPropertiesTest { @Serializable data class SecondChild(override val firstProperty: Long, override val secondProperty: String) : BaseClass() + @Serializable + data class CompositeClass(val item: BaseClass) + @Test fun testPropertiesDeserialization() { val props = mapOf( @@ -44,7 +48,71 @@ class SealedClassSerializationFromPropertiesTest { val instanceProperties = Properties.encodeToMap(instance) + assertEquals("FIRSTCHILD", instanceProperties["type"]) assertEquals(1L, instanceProperties["firstProperty"]) assertEquals("one", instanceProperties["secondProperty"]) } + + @Test + fun testWrappedPropertiesDeserialization() { + val props = mapOf( + "0.type" to "FIRSTCHILD", + "0.firstProperty" to 1L, + "0.secondProperty" to "one", + "1.type" to "SECONDCHILD", + "1.firstProperty" to 2L, + "1.secondProperty" to "two" + ) + + val instances: List = Properties.decodeFromMap(props) + + val expected = listOf(FirstChild(1, "one"), SecondChild(2, "two")) + assertEquals(expected, instances) + } + + @Test + fun testWrappedPropertiesSerialization() { + val instances: List = listOf( + FirstChild(firstProperty = 1L, secondProperty = "one"), + SecondChild(firstProperty = 2L, secondProperty = "two") + ) + + val instanceProperties = Properties.encodeToMap(instances) + + assertEquals("FIRSTCHILD", instanceProperties["0.type"]) + assertEquals(1L, instanceProperties["0.firstProperty"]) + assertEquals("one", instanceProperties["0.secondProperty"]) + assertEquals("SECONDCHILD", instanceProperties["1.type"]) + assertEquals(2L, instanceProperties["1.firstProperty"]) + assertEquals("two", instanceProperties["1.secondProperty"]) + } + + @Test + fun testCompositeClassPropertiesDeserialization() { + val props = mapOf( + "item.type" to "SECONDCHILD", + "item.firstProperty" to 7L, + "item.secondProperty" to "nothing" + ) + + val composite: CompositeClass = Properties.decodeFromMap(props) + + assertEquals(CompositeClass(SecondChild(7L, "nothing")), composite) + } + + @Test + fun testCompositeClassPropertiesSerialization() { + val composite = CompositeClass( + item = FirstChild( + firstProperty = 5L, + secondProperty = "something" + ) + ) + + val compositeProperties = Properties.encodeToMap(composite) + + assertEquals("FIRSTCHILD", compositeProperties["item.type"]) + assertEquals(5L, compositeProperties["item.firstProperty"]) + assertEquals("something", compositeProperties["item.secondProperty"]) + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index e43cbcce9f..ea94c998c7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ kotlin.version.snapshot=1.9.255-SNAPSHOT junit_version=4.12 jackson_version=2.10.0.pr1 -dokka_version=1.7.0 +dokka_version=1.8.10 native.deploy= validator_version=0.11.0 knit_version=0.4.0