diff options
author | Leonid Startsev <sandwwraith@users.noreply.github.com> | 2023-04-20 12:18:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-20 12:18:38 +0200 |
commit | fc9aef532349fa910394c03b1cc741a4ef575712 (patch) | |
tree | 00833814f5dfe0afadbb873f324b7959e5994232 /formats/json-tests/commonTest/src/kotlinx/serialization | |
parent | 508443504bd0609d117aef5467869427d5e26b35 (diff) | |
download | kotlinx.serialization-fc9aef532349fa910394c03b1cc741a4ef575712.tar.gz |
Fix value class encoding in various corner cases (#2242)
- Value class is located at top-level, but wraps non-primitive and thus does not fall in 'primitive on top-level' branch
- Value class is a subclass in a polymorphic hierarchy, but either is primitive or explicitly recorded without type info
Note that type info is omitted in the latter case and 'can't add type info to primitive' error is not thrown deliberately, as
there seems to be use-cases for that.
Fixes #1774
Fixes #2159
Diffstat (limited to 'formats/json-tests/commonTest/src/kotlinx/serialization')
2 files changed, 109 insertions, 2 deletions
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt index fdbb74af..0d30fc11 100644 --- a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt +++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/InlineClassesTest.kt @@ -22,7 +22,7 @@ data class SimpleContainerForUInt(val i: UInt) @JvmInline value class MyUInt(val m: Int) -object MyUIntSerializer: KSerializer<MyUInt> { +object MyUIntSerializer : KSerializer<MyUInt> { override val descriptor = UInt.serializer().descriptor override fun serialize(encoder: Encoder, value: MyUInt) { encoder.encodeInline(descriptor).encodeInt(value.m) @@ -73,13 +73,46 @@ value class ResourceKind(val kind: SampleEnum) @Serializable data class ResourceIdentifier(val id: ResourceId, val type: ResourceType, val type2: ValueWrapper) -@Serializable @JvmInline +@Serializable +@JvmInline value class ValueWrapper(val wrapped: ResourceType) +@Serializable +@JvmInline +value class Outer(val inner: Inner) + +@Serializable +data class Inner(val n: Int) + +@Serializable +data class OuterOuter(val outer: Outer) + +@Serializable +@JvmInline +value class WithList(val value: List<Int>) + class InlineClassesTest : JsonTestBase() { private val precedent: UInt = Int.MAX_VALUE.toUInt() + 10.toUInt() @Test + fun withList() = noLegacyJs { + val withList = WithList(listOf(1, 2, 3)) + assertJsonFormAndRestored(WithList.serializer(), withList, """[1,2,3]""") + } + + @Test + fun testOuterInner() = noLegacyJs { + val o = Outer(Inner(10)) + assertJsonFormAndRestored(Outer.serializer(), o, """{"n":10}""") + } + + @Test + fun testOuterOuterInner() = noLegacyJs { + val o = OuterOuter(Outer(Inner(10))) + assertJsonFormAndRestored(OuterOuter.serializer(), o, """{"outer":{"n":10}}""") + } + + @Test fun testTopLevel() = noLegacyJs { assertJsonFormAndRestored( ResourceType.serializer(), diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt new file mode 100644 index 00000000..f3b482f1 --- /dev/null +++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/inline/ValueClassesInSealedHierarchyTest.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.features.inline + +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlinx.serialization.test.* +import kotlin.jvm.* +import kotlin.test.* + +class ValueClassesInSealedHierarchyTest : JsonTestBase() { + @Test + fun testSingle() = noLegacyJs { + val single = "foo" + assertJsonFormAndRestored( + AnyValue.serializer(), + AnyValue.Single(single), + "\"$single\"" + ) + } + + @Test + fun testComplex() = noLegacyJs { + val complexJson = """{"id":"1","name":"object"}""" + assertJsonFormAndRestored( + AnyValue.serializer(), + AnyValue.Complex(mapOf("id" to "1", "name" to "object")), + complexJson + ) + } + + @Test + fun testMulti() = noLegacyJs { + val multiJson = """["list","of","strings"]""" + assertJsonFormAndRestored(AnyValue.serializer(), AnyValue.Multi(listOf("list", "of", "strings")), multiJson) + } +} + + +// From https://github.com/Kotlin/kotlinx.serialization/issues/2159 +@Serializable(with = AnyValue.Companion.Serializer::class) +sealed interface AnyValue { + + @JvmInline + @Serializable + value class Single(val value: String) : AnyValue + + @JvmInline + @Serializable + value class Multi(val values: List<String>) : AnyValue + + @JvmInline + @Serializable + value class Complex(val values: Map<String, String>) : AnyValue + + @JvmInline + @Serializable + value class Unknown(val value: JsonElement) : AnyValue + + companion object { + object Serializer : JsonContentPolymorphicSerializer<AnyValue>(AnyValue::class) { + + override fun selectDeserializer(element: JsonElement): DeserializationStrategy<AnyValue> = + when { + element is JsonArray && element.all { it is JsonPrimitive && it.isString } -> Multi.serializer() + element is JsonObject && element.values.all { it is JsonPrimitive && it.isString } -> Complex.serializer() + element is JsonPrimitive && element.isString -> Single.serializer() + else -> Unknown.serializer() + } + } + } +} |