Home > other >  How to parse this such json in Kotlin with GSON?
How to parse this such json in Kotlin with GSON?

Time:12-02

I have JSON object like this

{
"codemap":{
"codeOfItem1":"titleOfItem1",
"codeOfItem2":"titleOfItem2",
"codeOfItem3":"titleOfItem3",
"codeOfItem4":"titleOfItem4"
},
"items":{
"titleOfItem1":{
"attribute1":"value1",
"atttribute2":{
"subattr1":"value1_of_subattr1_for_item1",
"subattr2":"value1_of_subattr2_for_item1"
}
},
"titleOfItem2":{
"attribute1":"value2",
"atttribute2":{
"subattr1":"value1_of_subattr1_for_item2",
"subattr2":"value1_of_subattr2_for_item2"
}
},
"titleOfItem3":{
"attribute1":"value2",
"atttribute2":{
"subattr1":"value1_of_subattr1_for_item3",
"subattr2":"value1_of_subattr2_for_item3"
}
},
"titleOfItem4":{
"attribute1":"value2",
"atttribute2":{
"subattr1":"value1_of_subattr1_for_item4",
"subattr2":"value1_of_subattr2_for_item4"
}
}
}
}

How to parse it using GSON in Kotlin ? (Problem is that strings like titleOfItemXXX is both values in codemap map and key names in items map

I don't really like idea to go fully manual way like in How to parse this Json with no object name

Update: I don't want to get scheme like this (this is from Kotlin-to-JSON Android Studio Plugin)

import com.google.gson.annotations.SerializedName


data class x1(
    @SerializedName("codemap")
    val codemap: Codemap,
    @SerializedName("items")
    val items: Items
) {
    data class Codemap(
        @SerializedName("codeOfItem1")
        val codeOfItem1: String, // titleOfItem1
        @SerializedName("codeOfItem2")
        val codeOfItem2: String, // titleOfItem2
        @SerializedName("codeOfItem3")
        val codeOfItem3: String, // titleOfItem3
        @SerializedName("codeOfItem4")
        val codeOfItem4: String // titleOfItem4
    )

    data class Items(
        @SerializedName("titleOfItem1")
        val titleOfItem1: TitleOfItem1,
        @SerializedName("titleOfItem2")
        val titleOfItem2: TitleOfItem2,
        @SerializedName("titleOfItem3")
        val titleOfItem3: TitleOfItem3,
        @SerializedName("titleOfItem4")
        val titleOfItem4: TitleOfItem4
    ) {
        data class TitleOfItem1(
            @SerializedName("attribute1")
            val attribute1: String, // value1
            @SerializedName("atttribute2")
            val atttribute2: Atttribute2
        ) {
            data class Atttribute2(
                @SerializedName("subattr1")
                val subattr1: String, // value1_of_subattr1_for_item1
                @SerializedName("subattr2")
                val subattr2: String // value1_of_subattr2_for_item1
            )
        }

        data class TitleOfItem2(
            @SerializedName("attribute1")
            val attribute1: String, // value2
            @SerializedName("atttribute2")
            val atttribute2: Atttribute2
        ) {
            data class Atttribute2(
                @SerializedName("subattr1")
                val subattr1: String, // value1_of_subattr1_for_item2
                @SerializedName("subattr2")
                val subattr2: String // value1_of_subattr2_for_item2
            )
        }

        data class TitleOfItem3(
            @SerializedName("attribute1")
            val attribute1: String, // value2
            @SerializedName("atttribute2")
            val atttribute2: Atttribute2
        ) {
            data class Atttribute2(
                @SerializedName("subattr1")
                val subattr1: String, // value1_of_subattr1_for_item3
                @SerializedName("subattr2")
                val subattr2: String // value1_of_subattr2_for_item3
            )
        }

        data class TitleOfItem4(
            @SerializedName("attribute1")
            val attribute1: String, // value2
            @SerializedName("atttribute2")
            val atttribute2: Atttribute2
        ) {
            data class Atttribute2(
                @SerializedName("subattr1")
                val subattr1: String, // value1_of_subattr1_for_item4
                @SerializedName("subattr2")
                val subattr2: String // value1_of_subattr2_for_item4
            )
        }
    }
}

because I don't really known how much items I will have and which names they will use in production.

CodePudding user response:

I think you want dynamic-named property in the schema. In this case, declare it as Map:

data class Schema(val codemap: Map<String, String>, val items: Map<String, Item>) {
    data class Item(val attribute1: String, val atttribute2: Attr2) {
        data class Attr2(val subattr1: String, val subattr2: String)
    }
}

fun gsonDemo() {
    val json = """
        {
        "codemap":{
        "codeOfItem1":"titleOfItem1",
        "codeOfItem2":"titleOfItem2",
        "codeOfItem3":"titleOfItem3",
        "codeOfItem4":"titleOfItem4"
        },
        "items":{
        "titleOfItem1":{
        "attribute1":"value1",
        "atttribute2":{
        "subattr1":"value1_of_subattr1_for_item1",
        "subattr2":"value1_of_subattr2_for_item1"
        }
        },
        "titleOfItem2":{
        "attribute1":"value2",
        "atttribute2":{
        "subattr1":"value1_of_subattr1_for_item2",
        "subattr2":"value1_of_subattr2_for_item2"
        }
        },
        "titleOfItem3":{
        "attribute1":"value2",
        "atttribute2":{
        "subattr1":"value1_of_subattr1_for_item3",
        "subattr2":"value1_of_subattr2_for_item3"
        }
        },
        "titleOfItem4":{
        "attribute1":"value2",
        "atttribute2":{
        "subattr1":"value1_of_subattr1_for_item4",
        "subattr2":"value1_of_subattr2_for_item4"
        }
        }
        }
        }
    """.trimIndent()

    val obj = Gson().fromJson(json, Schema::class.java)
    println(obj.items[obj.codemap["codeOfItem3"]]?.atttribute2?.subattr1) // print value1_of_subattr1_for_item3
}

Note that Gson won't fail if some properties are missing, so all the values of properties may be null, although they are declared as non-nullable

CodePudding user response:

Looks like I forget about simple ways :(

Working answer:

data class TopLevel (
    @SerializedName("codemap")
    val codemap: Map<String, String>,
    @SerializedName("items")
    val items: Map<String, Item>
)

data class Item (
    @SerializedName("attribute1")
    val attribute1: Attribute1,
    @SerializedName("attribute2")
    val attribute2: Attribute2
)

data class Attribute2 (
    @SerializedName("subattr1")
    val subattr1: String,
    @SerializedName("subattr2")
    val subattr1: String
)

enum class Attribute1 {
    @SerializedName("DarkSide")
    DarkSide,
    @SerializedName("LightSide")
    LightSide
}


var gson: Gson = Gson()

val str=... //string with source JSON
val result = gson.fromJson(str, TopLeve::class.java)

Everything appears to work correctly.

  • Related