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.