4

The JSON file I'm pulling from unfortunately has a node with the same variable name but could have two different data types randomly. When I make a network call (using gson) I get the error:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a BEGIN_ARRAY but was int at line 1 column 5344 path $[1].medium

the JSON looks like

{
  "title": "Live JSON generator",
  "url": google.com,
  "medium": ["chicken", "radio", "room"] 
}
//However sometimes medium can be:
"medium": 259

My Serialized class looks like:

data class SearchItem(
    @SerializedName("title") var title: String,
    @SerializedName("url") var urlStr: String,
    @SerializedName("medium") val medium: List<String>? = null
) : Serializable {}

The way I'm making the network call is like this:

private val api: P1Api

fun onItemClicked(searchItem: SearchItem) {
   api.getCollections { response, error ->
      response.toString()
      val searchItems: List<SearchItem> = Util.gson?.fromJson<List<SearchItem>>(
                           response.get("results").toString()
                           , object : TypeToken<List<SearchItem>>() {}.type)?.toList()!!
...
      doStuffWithSearchItems(searchItems)
}

How do I handle both cases where "medium" can either be an array of strings or it could be an Int?

Ben Akin
  • 167
  • 2
  • 15

1 Answers1

3

You could write custom JsonDeserializer for this case:

class SearchItemCustomDeserializer: JsonDeserializer<SearchItem> {
    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): SearchItem {
        val obj = json.asJsonObject
        val title = obj.get("title").asString
        val url = obj.get("url").asString
        val mediumProp = obj.get("medium")
        val medium = if(mediumProp.isJsonArray) {
            mediumProp.asJsonArray.map { it.asString }
        } else {
            listOf(mediumProp.asString)
        }
        return SearchItem(
            title = title,
            urlStr = url,
            medium = medium
        )
    }
}

With this class you "manually" deserialize json to object. For medium property we check is this array or simple json primitive with function mediumProp.isJsonArray. And if answer is yes - then deserialize field as json array of strings mediumProp.asJsonArray.map { it.asString } Else deserialize the field as string.

And then we register our custom SearchItemCustomDeserializer on GsonBuilder using method registerTypeAdapter

val gson = GsonBuilder()
    .registerTypeAdapter(SearchItem::class.java, SearchItemCustomDeserializer())
    .create()

And after this you can use this gson instance to deserialize yours objects

ZSergei
  • 807
  • 10
  • 18