diff --git a/src/commonMain/kotlin/com/charleskorn/kaml/YamlContextualInput.kt b/src/commonMain/kotlin/com/charleskorn/kaml/YamlContextualInput.kt index 6e80a01d..627b3f5f 100644 --- a/src/commonMain/kotlin/com/charleskorn/kaml/YamlContextualInput.kt +++ b/src/commonMain/kotlin/com/charleskorn/kaml/YamlContextualInput.kt @@ -24,7 +24,11 @@ import kotlinx.serialization.modules.SerializersModule internal class YamlContextualInput(node: YamlNode, yaml: Yaml, context: SerializersModule, configuration: YamlConfiguration) : YamlInput(node, yaml, context, configuration) { override fun decodeElementIndex(descriptor: SerialDescriptor): Int = throw IllegalStateException("Must call beginStructure() and use returned Decoder") - override fun decodeValue(): Any = throw IllegalStateException("Must call beginStructure() and use returned Decoder") + override fun decodeValue(): Any = when (node) { + is YamlScalar -> node.content + is YamlNull -> throw UnexpectedNullValueException(node.path) + else -> throw IllegalStateException("Must call beginStructure() and use returned Decoder") + } override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder = createFor(node, yaml, serializersModule, configuration, descriptor) diff --git a/src/commonTest/kotlin/com/charleskorn/kaml/YamlReadingTest.kt b/src/commonTest/kotlin/com/charleskorn/kaml/YamlReadingTest.kt index 5709999d..f96f4aa8 100644 --- a/src/commonTest/kotlin/com/charleskorn/kaml/YamlReadingTest.kt +++ b/src/commonTest/kotlin/com/charleskorn/kaml/YamlReadingTest.kt @@ -1470,6 +1470,20 @@ class YamlReadingTest : FlatFunSpec({ } } + context("given some input for an object where the property value should be a sealed class (inline)") { + val input = """ + element: ! "abcdef" + """.trimIndent() + + context("parsing that input") { + val result = polymorphicYaml.decodeFromString(SealedWrapper.serializer(), input) + + test("deserializes it to a Kotlin object") { + result shouldBe SealedWrapper(TestSealedStructure.InlineSealedString("abcdef")) + } + } + } + context("given some input for an object where the property value is a literal") { val input = """ test: ! 42 @@ -1492,6 +1506,7 @@ class YamlReadingTest : FlatFunSpec({ value: -987 - ! value: 654 + - ! "testing" - ! value: "tests" """.trimIndent() @@ -1505,6 +1520,7 @@ class YamlReadingTest : FlatFunSpec({ TestSealedStructure.SimpleSealedString(null), TestSealedStructure.SimpleSealedInt(-987), TestSealedStructure.SimpleSealedInt(654), + TestSealedStructure.InlineSealedString("testing"), TestSealedStructure.SimpleSealedString("tests"), ) } @@ -1603,11 +1619,11 @@ class YamlReadingTest : FlatFunSpec({ val exception = shouldThrow { polymorphicYaml.decodeFromString(TestSealedStructure.serializer(), input) } exception.asClue { - it.message shouldBe "Unknown type 'someOtherType'. Known types are: sealedInt, sealedString" + it.message shouldBe "Unknown type 'someOtherType'. Known types are: inlineString, sealedInt, sealedString" it.line shouldBe 1 it.column shouldBe 1 it.typeName shouldBe "someOtherType" - it.validTypeNames shouldBe setOf("sealedInt", "sealedString") + it.validTypeNames shouldBe setOf("inlineString", "sealedInt", "sealedString") it.path shouldBe YamlPath.root } } @@ -1624,11 +1640,11 @@ class YamlReadingTest : FlatFunSpec({ val exception = shouldThrow { polymorphicYaml.decodeFromString(TestSealedStructure.serializer(), input) } exception.asClue { - it.message shouldBe "Unknown type 'someOtherType'. Known types are: sealedInt, sealedString" + it.message shouldBe "Unknown type 'someOtherType'. Known types are: inlineString, sealedInt, sealedString" it.line shouldBe 1 it.column shouldBe 1 it.typeName shouldBe "someOtherType" - it.validTypeNames shouldBe setOf("sealedInt", "sealedString") + it.validTypeNames shouldBe setOf("inlineString", "sealedInt", "sealedString") it.path shouldBe YamlPath.root } } @@ -1818,11 +1834,11 @@ class YamlReadingTest : FlatFunSpec({ val exception = shouldThrow { polymorphicYaml.decodeFromString(TestSealedStructure.serializer(), input) } exception.asClue { - it.message shouldBe "Unknown type 'someOtherType'. Known types are: sealedInt, sealedString" + it.message shouldBe "Unknown type 'someOtherType'. Known types are: inlineString, sealedInt, sealedString" it.line shouldBe 1 it.column shouldBe 7 it.typeName shouldBe "someOtherType" - it.validTypeNames shouldBe setOf("sealedInt", "sealedString") + it.validTypeNames shouldBe setOf("inlineString", "sealedInt", "sealedString") it.path shouldBe YamlPath.root.withMapElementKey("type", Location(1, 1)).withMapElementValue(Location(1, 7)) } } @@ -2028,11 +2044,11 @@ class YamlReadingTest : FlatFunSpec({ val exception = shouldThrow { polymorphicYaml.decodeFromString(TestSealedStructure.serializer(), input) } exception.asClue { - it.message shouldBe "Unknown type 'someOtherType'. Known types are: sealedInt, sealedString" + it.message shouldBe "Unknown type 'someOtherType'. Known types are: inlineString, sealedInt, sealedString" it.line shouldBe 1 it.column shouldBe 7 it.typeName shouldBe "someOtherType" - it.validTypeNames shouldBe setOf("sealedInt", "sealedString") + it.validTypeNames shouldBe setOf("inlineString", "sealedInt", "sealedString") it.path shouldBe YamlPath.root.withMapElementKey("kind", Location(1, 1)).withMapElementValue(Location(1, 7)) } } diff --git a/src/commonTest/kotlin/com/charleskorn/kaml/YamlWritingTest.kt b/src/commonTest/kotlin/com/charleskorn/kaml/YamlWritingTest.kt index 22c8e5f9..2ed733d6 100644 --- a/src/commonTest/kotlin/com/charleskorn/kaml/YamlWritingTest.kt +++ b/src/commonTest/kotlin/com/charleskorn/kaml/YamlWritingTest.kt @@ -845,6 +845,18 @@ class YamlWritingTest : FlatFunSpec({ } } + context("serializing a sealed type (inline)") { + val input = TestSealedStructure.InlineSealedString("abc") + val output = polymorphicYaml.encodeToString(TestSealedStructure.serializer(), input) + val expectedYaml = """ + ! "abc" + """.trimIndent() + + test("returns the value serialized in the expected YAML form") { + output shouldBe expectedYaml + } + } + context("serializing an unsealed type") { val input = UnsealedString("blah") val output = polymorphicYaml.encodeToString(PolymorphicSerializer(UnsealedClass::class), input) @@ -883,11 +895,24 @@ class YamlWritingTest : FlatFunSpec({ } } + context("serializing a polymorphic value (inline) as a property value") { + val input = SealedWrapper(TestSealedStructure.InlineSealedString("abc")) + val output = polymorphicYaml.encodeToString(SealedWrapper.serializer(), input) + val expectedYaml = """ + element: ! "abc" + """.trimIndent() + + test("returns the value serialized in the expected YAML form") { + output shouldBe expectedYaml + } + } + context("serializing a list of polymorphic values") { val input = listOf( TestSealedStructure.SimpleSealedInt(5), TestSealedStructure.SimpleSealedString("some test"), TestSealedStructure.SimpleSealedInt(-20), + TestSealedStructure.InlineSealedString("more test"), TestSealedStructure.SimpleSealedString(null), null, ) @@ -901,6 +926,7 @@ class YamlWritingTest : FlatFunSpec({ value: "some test" - ! value: -20 + - ! "more test" - ! value: null - null diff --git a/src/commonTest/kotlin/com/charleskorn/kaml/testobjects/PolymorphicTestObjects.kt b/src/commonTest/kotlin/com/charleskorn/kaml/testobjects/PolymorphicTestObjects.kt index 72786a6a..b38af980 100644 --- a/src/commonTest/kotlin/com/charleskorn/kaml/testobjects/PolymorphicTestObjects.kt +++ b/src/commonTest/kotlin/com/charleskorn/kaml/testobjects/PolymorphicTestObjects.kt @@ -28,16 +28,22 @@ import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.modules.SerializersModule +import kotlin.jvm.JvmInline @Serializable -sealed class TestSealedStructure { +sealed interface TestSealedStructure { @Serializable @SerialName("sealedInt") - data class SimpleSealedInt(val value: Int) : TestSealedStructure() + data class SimpleSealedInt(val value: Int) : TestSealedStructure @Serializable @SerialName("sealedString") - data class SimpleSealedString(val value: String?) : TestSealedStructure() + data class SimpleSealedString(val value: String?) : TestSealedStructure + + @Serializable + @SerialName("inlineString") + @JvmInline + value class InlineSealedString(val value: String) : TestSealedStructure } @Serializable