I am working with an API that can have different types for it's attributes
The attributes can either be Ids or Objects
I want to build a generalized type that handles this for me with Gson serialization.
Example:
"platforms": [
6
]
"platforms": [
{
"id": 6,
"name": "PC (Microsoft Windows)",
"slug": "win",
"url": "https://www.igdb.com/platforms/win",
"created_at": 1297639288000,
"updated_at": 1470063140518,
"website": "http://windows.microsoft.com/",
"alternative_name": "mswin"
}
]
I am working with Kotlin and have started building my Generalizable class
data class ObjectType<T>(
var Id: Long? = null,
var expand: T? = null
)
I am currently stuck in constructing my JsonDeserializer, as it needs a return of type T which in my case can be both an Int or an Object. I have tried to replace the T with ObjectType which works 'better' but cannot handle the cases when the JSON is an array.
I am currently trying to make it work with just the Generalized Type T as I can set the type as List> instead.
Current Implementation:
class ObjectDeserializer<T> : JsonDeserializer<T> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): T {
if (json != null) {
if (json.isJsonArray) {
val struct: T = Gson().fromJson(json, T::class.java) as T
return struct
} else {
val id = Gson().fromJson(json, Long::class.java)
//return ObjectType(id, null)
}
}
return T as T
}
}
I would love some input on how to solve this.
Your implementation has some issues and inconsistencies. First you have to make sure to deserialize ObjectType<T>
. Thus you have to declare the class as:
class ObjectDeserializer<T> : JsonDeserializer<ObjectType<T>>
It would also be easier to assume that all parameters are non-null:
override fun deserialize(json: JsonElement, typeOfT: Type,
context: JsonDeserializationContext): ObjectType<T>
Now you can use typeOfT
which is actually the type of T
in JsonDeserializer
, not in ObjectDeserializer
. Therefore it's the type of ObjectType<T>
you need to deserialize. To move to the next step you need to find the actual type of T:
val objectTypeType = typeOfT as ParameterizedType
val actualTypeOfT = objectTypeType.getActualTypeArguments()[0]
As the next step you need to figure out the contents of json
. In your case you won't ever find an array, but an object or a long:
return if (json.isJsonObject()) {
val struct: T = context.deserialize(json, actualTypeOfT)
ObjectType(expand = struct)
} else {
val id = json.getAsLong()
ObjectType(Id = id)
}
Here you return the ObjectType
instances without any error handling, which you might need to add as well.
Then you should provide this deserializer to Gson by:
registerTypeAdapter(ObjectType::class.java, ObjectDeserializer<Any>())
Whenever Gson needs to deserialize an ObjectType<TheType>
, it finds the instance of ObjectDeserializer
and provides ObjectType<TheType>
as typeOfT
to deserialize
.