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