Home > Net >  How to make a generic serialized name in retrofit?
How to make a generic serialized name in retrofit?

Time:02-25

Most of my API calls return something like this:

{
  "message": str,
  "status": str,
  "different_name_depending_on_endpoint":{
    // bunch of stuff
  },
}

How can I make the name that goes in the "different_name_depending_on_endpoint" key generic? Like so :

data class ReturnAPI<T>(
    @SerializedName("message")
    val message: String,
    @SerializedName("status")
    val status: String,
    @SerializedName("how do I make this generic")
    val data: T
)

Otherwise for every endpoint I have to create a separate data class for the api return, and a separate data class for the data field, which is impractical. There must be a way to make it generic, right? Or to tell Retrofit to try to fill the data field with whatever else is in the JSON file that isn't message or status.

CodePudding user response:

Or to tell Retrofit to try to fill the data field with whatever else is in the JSON file that isn't message or status

Yes, you can write a custom deserializer for ReturnAPI type:

@JsonAdapter(ReturnApiTypeAdapter::class)
data class ReturnAPI<T>(
    val message: String,
    val status: String,
    val data: T
)

class ReturnApiTypeAdapter : JsonDeserializer<ReturnAPI<*>> {

    @Throws(JsonParseException::class)
    override fun deserialize(
        json: JsonElement,
        typeOfT: Type,
        context: JsonDeserializationContext
    ): ReturnAPI<*>? {
        if (json.isJsonNull) {
            return null
        }
        val jsonObject = json.asJsonObject
        // get actual type of Data
        val typeOfData = (typeOfT as ParameterizedType)
            .actualTypeArguments[0]

        var message: String? = null
        var status: String? = null
        var data: Any? = null

        for (key in jsonObject.keySet()) {
            when (key) {
                "message" -> message = jsonObject.getAsJsonPrimitive(key).asString
                "status" -> status = jsonObject.getAsJsonPrimitive(key).asString
                else -> data = context.deserialize(jsonObject.get(key), typeOfData)
            }
        }
        // optional checks
        check(message != null && status != null) {
            "Failed parsing"
        }
        return ReturnAPI(message, status, data)
    }
}
  • Related