Trouble parsing a JSON string with unknown keys using Retrofit and Gson

Viewed 313

I have a JSON response that includes unknown keys (the numbers), which I'm finding difficult to parse using the Gson converter. The cut-down version is

{
  "list": {
    "14": {
      "nickname": "Dave",
      "fullname": "David Collins"
    },
    "68": {
      "nickname": "Phil",
      "fullname": "Phillip Jordan"
    }
  },
  "action": "load",
  "status": "LOADED"
}

The following class structure gives an error Expected BEGIN_OBJECT but was NUMBER at line 1 column 23 path $.list..

data class NameNW(
    val fullname: String,
    val nickname: String
)

data class NamesListNWEntity(
    val action: String,
    val list: Map<Int, Map<String, NameNW>>,
    val status: String
)

I'm not sure why it's expecting BEGIN_OBJECT when the type is Map<Int... (or perhaps it's not seeing the '{' before the number when it's clearly there), so I'm stuck here. How do I get it to parse the string? Even better, how do I get it to record the number for NameNW? If it's not possible, I can adjust the server output, but that means updating a lot of code on the web client as well, which I'd rather avoid.

My Retrofit code is

interface Network  {

    @FormUrlEncoded
    @POST("serverfile")
    suspend fun getNames(
        @Field("action") action: String,
    ): NamesListNWEntity
}

class RetrofitWithCookie @Inject constructor(
    context: Context,
    gson: Gson
) {
    private val mContext = context
    private val gson = gson

    fun createRetrofit(): Retrofit {
        val client: OkHttpClient
        val builder = OkHttpClient.Builder()
        builder.addInterceptor(AddCookiesInterceptor(mContext))
        builder.addInterceptor(ReceivedCookiesInterceptor(mContext))
        client = builder.build()

        return Retrofit.Builder()
            .baseUrl("http://192.168.0.19/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }
}

And I'm calling it using val namesListNWEntity = Network.getNames("load")

1 Answers

Try with the following code.

data class NameNW(
    val fullname: String,
    val nickname: String
)

data class NamesListNWEntity(
    val action: String,
    val list: Map<String, NameNW>,
    val status: String
)

// You can also test with static json string
private fun test() {
    val apiResponse = "{\n" +
            "  \"list\": {\n" +
            "    \"14\": {\n" +
            "      \"nickname\": \"Dave\",\n" +
            "      \"fullname\": \"David Collins\"\n" +
            "    },\n" +
            "    \"68\": {\n" +
            "      \"nickname\": \"Phil\",\n" +
            "      \"fullname\": \"Phillip Jordan\"\n" +
            "    }\n" +
            "  },\n" +
            "  \"action\": \"load\",\n" +
            "  \"status\": \"LOADED\"\n" +
            "}"

    val namesListNWEntity: NamesListNWEntity = Gson().fromJson(apiResponse, NamesListNWEntity::class.java)
}
Related