Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to deserialise Nested-Tables? #255

Open
Kinchkun opened this issue Jan 16, 2024 · 1 comment
Open

How to deserialise Nested-Tables? #255

Kinchkun opened this issue Jan 16, 2024 · 1 comment

Comments

@Kinchkun
Copy link

Cheers,

thank you for this library :)

Assuming I have the following case:

@Serializable
data class Animals(
    val animals: Map<String, Animal>
)

@Serializable
data class Animal(
    val name: String,
    val vocal: String
)

@Test
fun `can parse animals`() {
    // language=toml
    val tomlString = """
    [animals."my cat"]
    name = "maunz"
    vocal = "miau"

    [animals."my dog"]
    name = "bello"
    vocal = "wuff"
    """.trimIndent()
    val animals = Toml.decodeFromString<Animals>(tomlString)
}

I got the following error:

com.akuleshov7.ktoml.exceptions.IllegalTypeException: Line 1: 
            You are trying to decode a nested Table animals."my cat" with a <Map> type to some primitive type.
            For example: 
            [a]
              [a.b]
                  a = 2
                  
            should be decoded to Map<String, Map<String, Long>>, but not to Map<String, Long>

Firstly, I don't think this error message is correct. "Animal" is not a primitive type, or?

However, when I follow the suggestions and change animals: Map<String, Animal> to animals: Map<String, Map<String, Animal>> I didn't get an error, but the types are wrong:

image

As you can see I got Map<String, Map<String,String>>.

The other way however works like charm:

@Test
fun `can serialise animals`() {
    val animals = Animals(mapOf(
        "my cat" to Animal("maunz", "miau"),
        "my dog" to Animal("bello", "wuff"),
    ))

    val tomlString = Toml.encodeToString(animals)
    println(tomlString) 
/* Produces
[animals."my cat"]
    name = "maunz"
    vocal = "miau"

[animals."my dog"]
    name = "bello"
    vocal = "wuff"
*/
}

Do I misunderstand something?

Kind regards

@orchestr7
Copy link
Owner

orchestr7 commented Jan 19, 2024

Hi! Thank you for your very good question ❤️

Actually by the initial implementation of ktoml we expected to have strict naming schema of the decoded type (where you was not able to use Map, but had to explicitly name your fields like “my dog” and “my cat”):

val `my dog`: Animal

this will work in your case if you know the names of nested tables.

Later due to a number of requests, we decided to add anonymous fields and decode them to a Map. And looks like I forgot to support a corner case: when you don’t know the names of nested tables, but know their type.

It’s a bug, need to fix it…

In your case there is a quick workaround with nested map: Map<String, Map<String, String> - that should work. Or you may name nested tables explicitly as I pointed above with my dog example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants