From 703f8e7a5e6031567ae6d322af4575f58ba429ab Mon Sep 17 00:00:00 2001 From: Sergey Shanshin Date: Wed, 21 Oct 2020 19:59:51 +0300 Subject: [PATCH] Add support of decoding map in the root of HOCON config (#1106) Fixes #1046 --- formats/hocon/build.gradle | 1 + .../kotlinx/serialization/hocon/Hocon.kt | 4 +- .../hocon/HoconRootObjectsTest.kt | 81 +++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 formats/hocon/src/test/kotlin/kotlinx/serialization/hocon/HoconRootObjectsTest.kt diff --git a/formats/hocon/build.gradle b/formats/hocon/build.gradle index b2b233e357..ec751a58e9 100644 --- a/formats/hocon/build.gradle +++ b/formats/hocon/build.gradle @@ -23,5 +23,6 @@ dependencies { api 'com.typesafe:config:1.3.2' + testCompile "org.jetbrains.kotlin:kotlin-test" testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/formats/hocon/src/main/kotlin/kotlinx/serialization/hocon/Hocon.kt b/formats/hocon/src/main/kotlin/kotlinx/serialization/hocon/Hocon.kt index 8e97ad7ab5..708875c2c6 100644 --- a/formats/hocon/src/main/kotlin/kotlinx/serialization/hocon/Hocon.kt +++ b/formats/hocon/src/main/kotlin/kotlinx/serialization/hocon/Hocon.kt @@ -123,7 +123,9 @@ public sealed class Hocon( when { descriptor.kind.listLike -> ListConfigReader(conf.getList(currentTag)) descriptor.kind.objLike -> if (ind > -1) ConfigReader(conf.getConfig(currentTag)) else this - descriptor.kind == StructureKind.MAP -> MapConfigReader(conf.getObject(currentTag)) + descriptor.kind == StructureKind.MAP -> + // if current tag is null - map in the root of config + MapConfigReader(if (currentTagOrNull != null) conf.getObject(currentTag) else conf.root()) else -> this } } diff --git a/formats/hocon/src/test/kotlin/kotlinx/serialization/hocon/HoconRootObjectsTest.kt b/formats/hocon/src/test/kotlin/kotlinx/serialization/hocon/HoconRootObjectsTest.kt new file mode 100644 index 0000000000..f4d87cf982 --- /dev/null +++ b/formats/hocon/src/test/kotlin/kotlinx/serialization/hocon/HoconRootObjectsTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.hocon + +import com.typesafe.config.ConfigFactory +import kotlinx.serialization.Serializable +import org.junit.Ignore +import org.junit.Test +import kotlin.test.* + +class HoconRootMapTest { + private val configForRootMap = """ + key1 { + a = "text1" + b = 11 + } + + key2 { + a = "text2" + b = 12 + } + + key3 { + a = "text3" + b = 13 + } + """ + private val configWithEmptyObject = "{}" + private val configWithRootList = "[foo, bar]" + private val emptyConfig = "" + + @Serializable + data class CompositeValue( + val a: String, + val b: Int + ) + + @Test + fun testConfigWithRootMap() { + val config = ConfigFactory.parseString(configForRootMap) + val obj = Hocon.decodeFromConfig>(config) + + assertEquals(CompositeValue("text1", 11), obj["key1"]) + assertEquals(CompositeValue("text2", 12), obj["key2"]) + assertEquals(CompositeValue("text3", 13), obj["key3"]) + } + + @Test + fun testEmptyObjectDecode() { + val config = ConfigFactory.parseString(configWithEmptyObject) + // non-null map decoded from empty object as empty map + val map = Hocon.decodeFromConfig>(config) + assertTrue(map.isEmpty()) + + // nullable map decoded from empty object as null - not obvious + assertNull(Hocon.decodeFromConfig?>(config)) + + // root-level list in config not supported but nullable list can be decoded from empty object + assertNull(Hocon.decodeFromConfig?>(config)) + } + + @Ignore + @Test + fun testErrors() { + // because com.typesafe:config lib not support list in root we can't decode non-null list + val config = ConfigFactory.parseString(configWithEmptyObject) + assertFailsWith { + Hocon.decodeFromConfig>(config) + } + + // because com.typesafe:config lib not support list in root it fails while parsing + assertFailsWith { + ConfigFactory.parseString(configWithRootList) + } + + // com.typesafe:config lib parse empty config as empty object + ConfigFactory.parseString(emptyConfig) + } +}