Search code examples
kotlinretrofit2okhttp

How to convert json object with objects to json array with objects


I have a json object that looks like this.

{
  "Items": {
    "zzzz": {
      "id": "zzzz",
      "title": "qqqqqqq",
      "notifications": []
    },
    "rrrrr": {
      "id": "rrrrr",
      "title": "rrrrrrrrrrrrrrrrrr",
      "notifications": []
    },
    "eeeee": {
      "id": "eeeee",
      "title": "eeeeeeeeeeeeeeeeeeee",
      "notifications": []
    },
    "wwww": null,
    "dddddd": {
      "id": "dddddd",
      "title": "ddddddddddddddddddddddddd",
      "notifications": []
    },
    "qqq": {
      "id": "qqq",
      "title": "qqqqqqqqqqqqqqqqqqqqqq",
      "notifications": []
    },
    "rrrrrr": null
  }
}

My data class:

data class Response( 
                    val Items: List<Notification>
                    ........)
data ckass Notification(
                    val id : String,
                    val title: String,
                    val notifications: List<...>,

I need a List with objects zzzz,rrrr and so on to get into the data class with val items. But I can't figure out how to convert the incoming json object to a json array

I wanted to use my own deserializer, but in my case it won't help because I use one instance of okhttp and retrofit for all requests. And also, a response always comes from the server in the form of:

  "Items": {
       //other request body
  },
.....
}

Solution

  • I am not sure what deserializer you using. Here's a solution assuming Jackson, but maybe you can take the ideas from this if you are using Gson, etc.

    The key idea is to use an intermediary object to deserialize into - a Map whose key values you ignore:

    // your desired data classes
    data class Response(
        val items: List<Notification>,
    )
    
    data class Notification(
        val id: String,
        val title: String,
        val notifications: List<Any>,
    )
    
    // an intermediary object
    // I notice that some Notifications are null, hence the `?`
    data class ResponseWithObjects(
        @JsonProperty("Items") // this is needed for Jackson since I used a conventional variable name Kotlin side
        val items: Map<String, Notification?>,
    )
    
    fun main(args: Array<String>) {
        val actualResponse: ResponseWithObjects = TestUtils.deserialize("/test.json", ResponseWithObjects::class)
        println(actualResponse)
        val desiredResponse = Response(
            items = actualResponse.items
                .values.filterNotNull() // assuming you don't want the null notifications in the resultant array
                .toList(),
        )
        println(desiredResponse)
    }