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)
}
}
