Search code examples
jsonkotlinmoshi

Parse json with moshi where one of the fields is polymorphic


I want to parse the following JSON API response into the list of objects. As you can see, the field "record" is polymorphic.

[
  {
    "t_id": "638975A6-3E5A-4D38-82A0-1CEF7A006AC6",
    "table": "ticket",
    "record": {
      "ticket_id": "111",
      "fk_project": "29446",
      "fk_phase": "64379",
      "fk_status": "159406",
      // many more different fields
      "created": "2023-06-19 15:00:26"
    }
  },
  {
    "t_id": "912975A6-AB5A-5D40-12B2-1CEF7AAAAC23",
    "table": "comment",
    "record": {
      "comment_id": "25666",
      "role_id": "71758",
      "resource": "list",
      // many more different fields
      "created": "2023-10-03 22:28:21"
    }
  }
]

My code that uses moshi looks like this:

@GET("api")
suspend fun api(): Response<List<MyResponse>>

@JsonClass(generateAdapter = true)
data class MyResponse(
    val t_id: String,
    val table: String,
    val record: Map<String, String?>
)

But I get com.squareup.moshi.JsonEncodingException: Use JsonReader.setLenient(true) to accept malformed JSON at path $ with my implementation.

I have seen this question, but in my case there aren't just 2 types, but 100+ (ticket, comment, isssue ... 100 more). I also cannot use the Polymorphic Adapter because of the same reason. How can I parse this polymorphic field as Map<String, String?>?


Solution

  • Turns out there was no problem in parsing the polymorphic field as Map<String, String?>.

    The root cause was okhttp. I was manually setting the Content-Encoding to gzip, which disabled the okhttp decompression, so my json response was a compressed gibberish.

    Apparently, setting this header is something that you shouldn't do unless you want your own custom decompression. Okhttp adds this header and decompresses behind the scenes. See this.