Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse a JSON array into Map<String, String> using Kotlinx.serialization

I am writing a Kotlin multiplatform project (JVM/JS) and I am trying to parse a HTTP Json array response into a Map using Kotlinx.serialization

The JSON is something like this:

[{"someKey": "someValue"}, {"otherKey": "otherValue"}, {"anotherKey": "randomText"}]

So far, I am able to get that JSON as String, but I can't find any documentation to help me build a Map or another kind of object. All of it says how to serialize static objects.

I can't use @SerialName because the key is not fixed.

When I try to return a Map<String, String>, I get this error:

Can't locate argument-less serializer for class kotlin.collections.Map. For generic classes, such as lists, please provide serializer explicitly.

At the end, I would like to get either a Map<String, String> or a List<MyObject> where my object could be MyObject(val id: String, val value: String)

Is there a way to do that? Otherwise I am thinking in just writing a String reader to be able to parse my data.

like image 433
Rulo Mejía Avatar asked Apr 14 '19 12:04

Rulo Mejía


1 Answers

You can implement you own simple DeserializationStrategy like this:

object JsonArrayToStringMapDeserializer : DeserializationStrategy<Map<String, String>> {

    override val descriptor = SerialClassDescImpl("JsonMap")

    override fun deserialize(decoder: Decoder): Map<String, String> {

        val input = decoder as? JsonInput ?: throw SerializationException("Expected Json Input")
        val array = input.decodeJson() as? JsonArray ?: throw SerializationException("Expected JsonArray")

        return array.map {
            it as JsonObject
            val firstKey = it.keys.first()
            firstKey to it[firstKey]!!.content
        }.toMap()


    }

    override fun patch(decoder: Decoder, old: Map<String, String>): Map<String, String> =
        throw UpdateNotSupportedException("Update not supported")

}


fun main() {
    val map = Json.parse(JsonArrayToStringMapDeserializer, data)
    map.forEach { println("${it.key} - ${it.value}") }
}
like image 187
Alexander Egger Avatar answered Oct 25 '22 04:10

Alexander Egger