Home > Blockchain >  How to serialize/deserialize json with nested field in kotlin?
How to serialize/deserialize json with nested field in kotlin?

Time:11-19

I am using Json.decodeFromString<User>("json string") (https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)

model is like

data class User(val id: String, val name: String, val assets: List<Asset>)
data class Asset(val id: String, val sku: String, val name: String)

but input json is like

{
  "data": {
    "id": "userId",
    "name": "userName",
    "body": {
      "assets": [
        {
          "data": {
            "id": "assetId",
            "sku": "assetSku",
            "name": "assetName"
          }
        }
      ]
    }
  }
}

How can I parse json with serializer? Seems not able to parse with delegate and surrogate serializers easily.

CodePudding user response:

Your POJO seems to be wrong , every field needs to have name corresponding to json value , or use GSON's SerializedName annotation and Parse sing Gson.

Your User POJO should look something like this,

data class User (

   @SerializedName("data") var data : UserData

)
data class UserData(

   @SerializedName("id") var id : String,
   @SerializedName("name") var name : String,
   @SerializedName("body") var body : Body

)
data class Body (

   @SerializedName("assets") var assets : List<Assets>

)
data class Assets (

   @SerializedName("data") var data : AssetsData

)
data class AssetsData(

   @SerializedName("id") var id : String,
   @SerializedName("sku") var sku : String,
   @SerializedName("name") var name : String

)

for serializing and deserializing

dependencies {
    implementation 'com.google.code.gson:gson:2.8.9'
}
val gson = Gson()
val jsonValue = gson.toJson(User)

val jsonToUser = gson.fromJson(jsonValue ,User::class.java)

CodePudding user response:

Read about https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#under-the-hood-experimental

Tried something like this:

@Serializable(with = AssetSerializer::class)
data class Asset(val id: String, val sku: String, val name: String)

@Serializable(with = UserSerializer::class)
data class User(val id: String, val name: String, val assets: List<Asset>)

object AssetSerializer: KSerializer<Asset> {
    override val descriptor: SerialDescriptor =
    buildClassSerialDescriptor("Asset") {
        element("data", buildClassSerialDescriptor("data") {
            element("id", String.serializer().descriptor)
            element("sku", String.serializer().descriptor)
            element("name", String.serializer().descriptor)
        })
    }
    override fun serialize(encoder: Encoder, value: Asset) {
        require(encoder is JsonEncoder)
        encoder.encodeJsonElement(buildJsonObject {
            put("data", buildJsonObject {
                put("id", value.id)
                put("sku", value.sku)
                put("name", value.name)
            })
        })
    }
    override fun deserialize(decoder: Decoder): Asset {
        require(decoder is JsonDecoder)
        val root = decoder.decodeJsonElement()
        val element = root.jsonObject["data"]!!
        return Asset(
            id = element.jsonObject["id"]!!.jsonPrimitive.content,
            sku = element.jsonObject["sku"]!!.jsonPrimitive.content,
            name = element.jsonObject["name"]!!.jsonPrimitive.content,
        )
    }
}

object UserSerializer: KSerializer<User> {
    override val descriptor: SerialDescriptor =
    buildClassSerialDescriptor("User") {
        element("data", buildClassSerialDescriptor("data") {
            element("id", String.serializer().descriptor)
            element("name", String.serializer().descriptor)
            element("body", buildClassSerialDescriptor("body") {
                element("assets", ListSerializer(Asset.serializer()).descriptor)
            })
        })
    }
    override fun serialize(encoder: Encoder, value: User) {
        require(encoder is JsonEncoder)
        encoder.encodeJsonElement(buildJsonObject {
            put("data", buildJsonObject {
                put("id", value.id)
                put("name", value.name)
                put("body", buildJsonObject {
                    put("assets", JsonArray(value.assets.map { asset ->
                        encoder.json.encodeToJsonElement(asset)
                    }))
                })
            })
        })
    }
    override fun deserialize(decoder: Decoder): User {
        require(decoder is JsonDecoder)
        val root = decoder.decodeJsonElement()
        val element = root.jsonObject["data"]!!
        val assets = element
            .jsonObject["body"]!!
            .jsonObject["assets"]!!
            .jsonArray
            .map { asset ->
                decoder.json.decodeFromJsonElement(asset)
            }

        return Asset(
            id = element.jsonObject["id"]!!.jsonPrimitive.content,
            name = element.jsonObject["name"]!!.jsonPrimitive.content,
            assets = assets,
        )
    }
}
  • Related