How do I create a pojo class if I have a JsonArray and a dynamic JsonObject in a JsonArray?

35 views Asked by At

The following issue occurred while calling api using Retrofit on Android

Response json

[
  {
    "test1": 10,
    "test2": 20,
    "test3": 37,
    "test_list": [
      {
        "id": 11,
        "content": "AAA"
      }
    ]
  },

  {
    "test1": 23,
    "test2": 37,
    "test3": 62,
    "test_list": [
      {
        "id": 13,
        "content": "AAA"
      }
    ]
  },
  
  [
    {
      "test1": 33,
      "test2": 17,
      "test3": 67,
      "test_list": [
        {
          "id": 15,
          "content": "BBB"
        }
      ]
    }
  ]
]

There's a dynamic JsonObject in the JsonArray

//dynamic
{
    "test1": 23,
    "test2": 37,
    "test3": 62,
    "test_list": [
      {
        "id": 13,
        "content": "AAA"
      }
    ]
  }

If only this part exists, it can be solved in this way, but at the same time, there is a JsonArray, and the format of the JsonObject inside is the same as the JsonObject outside

//Impossible because of JsonArray
data class Response(
    val data : List<POJO>
)

The Response json format cannot be changed If anyone knows the answer, please help. Thank you

1

There are 1 answers

0
Sarah On

You can use a combination of Kotlin data classes and some manual parsing. Since the structure inside the JSON array can change, you'll need to use a custom deserializer to handle the dynamic JSON objects.

First, create the data classes for your JSON structure:

data class ResponseItem(
    val test1: Int,
    val test2: Int,
    val test3: Int,
    val test_list: List<TestListItem>
)

data class TestListItem(
    val id: Int,
    val content: String
)

Now, create a custom deserializer to handle the dynamic JSON objects within the JSON array. You can use Gson for this purpose. Add the following extension function to your code:

import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.lang.reflect.Type

class ResponseDeserializer : JsonDeserializer<ResponseItem> {
    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): ResponseItem {
        val jsonObject = json?.asJsonObject ?: throw JsonParseException("Invalid JSON")

        // Extract the fields you know exist
        val test1 = jsonObject.getAsJsonPrimitive("test1").asInt
        val test2 = jsonObject.getAsJsonPrimitive("test2").asInt
        val test3 = jsonObject.getAsJsonPrimitive("test3").asInt
        val testList = context?.deserialize<List<TestListItem>>(
            jsonObject.getAsJsonArray("test_list"),
            object : TypeToken<List<TestListItem>>() {}.type
        )

        // Create the ResponseItem object
        return ResponseItem(test1, test2, test3, testList ?: emptyList())
    }
}

Now, you can use Retrofit with this custom deserializer in your API interface:

import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

interface ApiService {
    @GET("your/api/endpoint")
    fun getResponse(): Call<List<ResponseItem>>
}

// Create a Retrofit instance with Gson and the custom deserializer
val retrofit = Retrofit.Builder()
    .baseUrl("your_base_url")
    .addConverterFactory(GsonConverterFactory.create(GsonBuilder().registerTypeAdapter(ResponseItem::class.java, ResponseDeserializer()).create()))
    .build()

// Create an instance of your ApiService
val apiService = retrofit.create(ApiService::class.java)

// Make the API call
val call = apiService.getResponse()
val response = call.execute()

if (response.isSuccessful) {
    val responseBody = response.body()
    // Handle the response as a list of ResponseItem objects
} else {
    // Handle the error
}

In this way, Retrofit and Gson can be used to deserialize JSON responses to dynamic JSON objects within a JSON array.