From 2151df14db50da7d0c847d62e484b6e7c1d2af25 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Mon, 6 Aug 2018 15:59:59 +0300 Subject: [PATCH] Don't throw NoSuchElement if key is missing in the map in `Mapper.readNotNullMark`, because tag can be only prefix for nested object Fixes #182 --- .../kotlin/kotlinx/serialization/Tagged.kt | 9 ++++-- .../kotlinx/serialization/MapperTest.kt | 32 +++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/runtime/common/src/main/kotlin/kotlinx/serialization/Tagged.kt b/runtime/common/src/main/kotlin/kotlinx/serialization/Tagged.kt index c452527941..0457c45bad 100644 --- a/runtime/common/src/main/kotlin/kotlinx/serialization/Tagged.kt +++ b/runtime/common/src/main/kotlin/kotlinx/serialization/Tagged.kt @@ -360,7 +360,12 @@ object Mapper { class InNullableMapper(val map: Map) : NamedValueInput() { override fun readTaggedValue(tag: String): Any = map.getValue(tag)!! - override fun readTaggedNotNullMark(tag: String): Boolean = map.getValue(tag) != null + override fun readTaggedNotNullMark(tag: String): Boolean { + return tag !in map || // in case of complex object, its fields are + // prefixed with dot and there are no 'clean' tag with object name. + // Invalid tags can be handled later, in .readValue + map.getValue(tag) != null + } } inline fun map(obj: T): Map { @@ -384,4 +389,4 @@ object Mapper { val m = InNullableMapper(map) return m.read() } -} \ No newline at end of file +} diff --git a/runtime/common/src/test/kotlin/kotlinx/serialization/MapperTest.kt b/runtime/common/src/test/kotlin/kotlinx/serialization/MapperTest.kt index 17a13d22d5..2a3e9c52a2 100644 --- a/runtime/common/src/test/kotlin/kotlinx/serialization/MapperTest.kt +++ b/runtime/common/src/test/kotlin/kotlinx/serialization/MapperTest.kt @@ -1,7 +1,6 @@ package kotlinx.serialization -import kotlin.test.Test -import kotlin.test.assertEquals +import kotlin.test.* class MapperTest { @@ -14,6 +13,13 @@ class MapperTest { @Serializable data class NullableData(val nullable: String?, val nullable2: String?, val property: String) + @Serializable + data class Category(var name: String? = null, + var subCategory: SubCategory? = null) + + @Serializable + data class SubCategory(var name: String? = null) + @Test fun testListTagStack() { val data = Data(listOf("element1"), "property") @@ -48,4 +54,26 @@ class MapperTest { assertEquals(data.nullable2, unmap.nullable2) assertEquals(data.property, unmap.property) } + + @Test + fun testNestedNull() { + val category = Category(name = "Name") + val map = Mapper.mapNullable(category) + val recreatedCategory = Mapper.unmapNullable(map) + assertEquals(category, recreatedCategory) + } + + @Test + fun testNestedNullable() { + val category = Category(name = "Name", subCategory = SubCategory()) + val map = Mapper.mapNullable(category) + val recreatedCategory = Mapper.unmapNullable(map) + assertEquals(category, recreatedCategory) + } + + @Test + fun failsOnIncorrectMaps() { + val map: Map = mapOf("name" to "Name") + assertFailsWith { Mapper.unmapNullable(map) } + } }