akuleshov7 / ktoml

Kotlin Multiplatform parser and compile-time serializer/deserializer for TOML format (Native, JS, JVM) based on KxS

Home Page:https://akuleshov7.github.io/ktoml

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

encodeToString produces wrong indentation for case when there are nested List among the tree

vlsi opened this issue · comments

class NestedListsTest {
    @Serializable
    data class Wrapper(
        val elements: List<Element>
    )

    @Serializable
    data class Element(
        val name: String,
        val subElements: List<SubElement>
    )

    @Serializable
    data class SubElement(
        val name: String,
        val description: String,
    )

    @Test
    fun test() {
        val data = Wrapper(
            elements = listOf(
                Element(
                    name = "element 1",
                    subElements = listOf(
                        SubElement("1.1", "d1.1"),
                        SubElement("1.2", "d1.2"),
                    )
                ),
            )
        )
        val serialized = Toml.encodeToString(data)

        Assert.assertEquals(
            serialized,
            """
            [[elements]]
                name = "element 1"

                [[elements.subElements]]
                    name = "1.1"
                    description = "d1.1"

                [[elements.subElements]]
                    name = "1.2"
                    description = "d1.2"
            """.trimIndent()
        )

        val deserialized = Toml.decodeFromString<Wrapper>(serialized)

        Assert.assertEquals(data, deserialized)
    }
}

com.akuleshov7:ktoml-core:0.5.1 yields

[[elements]]
    name = "element 1"

    [[elements.subElements]]
        name = "1.1"
        description = "d1.1"

[[elements.subElements]]
        name = "1.2"
        description = "d1.2"

The generated TOML does not parse. It would be nice if the error message included the problematic field name or something like that. Currently the error message provides little to no clue on why the parsing went wrong:

com.akuleshov7.ktoml.exceptions.MissingRequiredPropertyException: Invalid number of key-value arguments provided in the input for deserialization. Missing required property <0> from class <kotlin.collections.ArrayList> in the input. (In your deserialization class you have declared this field, but it is missing in the input)
	at app//com.akuleshov7.ktoml.decoders.TomlMainDecoder.checkMissingRequiredProperties(TomlMainDecoder.kt:200)
	at app//com.akuleshov7.ktoml.decoders.TomlMainDecoder.iterateOverTomlStructure(TomlMainDecoder.kt:258)
	at app//com.akuleshov7.ktoml.decoders.TomlMainDecoder.beginStructure(TomlMainDecoder.kt:220)
	at app//kotlinx.serialization.internal.AbstractCollectionSerializer.merge(CollectionSerializers.kt:29)
	at app//kotlinx.serialization.internal.AbstractCollectionSerializer.deserialize(CollectionSerializers.kt:43)
	at app//kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
	at app//kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:16)
	at app//com.akuleshov7.ktoml.decoders.TomlAbstractDecoder.decodeSerializableValue(TomlAbstractDecoder.kt:96)
	at app//kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
	at app//kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
	at app//com.example.NestedListsTest$Wrapper$$serializer.deserialize(TomlTest.kt:11)
	at app//com.example.NestedListsTest$Wrapper$$serializer.deserialize(TomlTest.kt:11)
	at app//kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
	at app//kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:16)
	at app//com.akuleshov7.ktoml.decoders.TomlAbstractDecoder.decodeSerializableValue(TomlAbstractDecoder.kt:96)
	at app//com.akuleshov7.ktoml.decoders.TomlMainDecoder$Companion.decode(TomlMainDecoder.kt:293)
	at app//com.akuleshov7.ktoml.Toml.decodeFromString(Toml.kt:47)
	at app//com.example.NestedListsTest.test(TomlTest.kt:66)

In case you wonder,

    @Serializable
    data class Wrapper(
        val elements: List<Element>
    )

    @Serializable
    data class Element(
        val name: String,
        val subElements: List<SubElement>
    )

    @Serializable
    data class SubElement(
        val name: String,
        val description: String,
        val subSubElements: List<SubSubElement>,
    )

    @Serializable
    data class SubSubElement(
        val name: String,
        val description: String,
    )

with

val data = Wrapper(
    elements = listOf(
        Element(
            name = "element 1",
            subElements = listOf(
                SubElement(
                    "1.1", "d1.1",
                    subSubElements =
                    listOf(
                        SubSubElement("1.1.1", "d1.1.1"),
                        SubSubElement("1.1.2", "d1.1.2")
                    )
                ),
                SubElement(
                    "1.2", "d1.2",
                    subSubElements =
                    listOf(
                        SubSubElement("1.2.1", "d1.2.1"),
                        SubSubElement("1.2.2", "d1.2.2"),
                    )
                ),
            )
        ),
        Element(
            name = "element 2",
            subElements = listOf(
                SubElement(
                    "2.1", "d2.1",
                    subSubElements =
                    listOf(
                        SubSubElement("2.1.1", "d2.1.1"),
                        SubSubElement("2.1.2", "d2.1.2"),
                    )
                ),
                SubElement(
                    "2.2", "d2.2",
                    subSubElements =
                    listOf(
                        SubSubElement("2.2.1", "d2.2.1"),
                        SubSubElement("2.2.2", "d2.2.2"),
                    )
                ),
            )
        ),
    )
)

yields

[[elements]]
    name = "element 1"

    [[elements.subElements]]
        name = "1.1"
        description = "d1.1"

        [[elements.subElements.subSubElements]]
            name = "1.1.1"
            description = "d1.1.1"

[[elements.subElements.subSubElements]]
            name = "1.1.2"
            description = "d1.1.2"

[[elements.subElements]]
        name = "1.2"
        description = "d1.2"

        [[elements.subElements.subSubElements]]
            name = "1.2.1"
            description = "d1.2.1"

[[elements.subElements.subSubElements]]
            name = "1.2.2"
            description = "d1.2.2"

[[elements]]
    name = "element 2"

    [[elements.subElements]]
        name = "2.1"
        description = "d2.1"

        [[elements.subElements.subSubElements]]
            name = "2.1.1"
            description = "d2.1.1"

[[elements.subElements.subSubElements]]
            name = "2.1.2"
            description = "d2.1.2"

[[elements.subElements]]
        name = "2.2"
        description = "d2.2"

        [[elements.subElements.subSubElements]]
            name = "2.2.1"
            description = "d2.2.1"

[[elements.subElements.subSubElements]]
            name = "2.2.2"
            description = "d2.2.2"

Decoding fails due to ArrayOfTables https://toml.io/en/v1.0.0#array-of-tables . It has mostly a zero support in our lib.

But spacing should be fixed, definitely