I am receiving a JSON data model that has a map wrapper Table. I'm trying to use generics to pass in the type that is beyond the wrapper but it's not translating well at runtime. Here's an example of my JSON file:
{
"Table": [
{
"paymentmethod_id": 1,
"paymentmethod_description": "Cash",
"paymentmethod_code": "Cash",
"paymentmethod_is_ach_onfile": false,
"paymentmethod_is_element": false,
"paymentmethod_is_reward": false,
"paymentmethod_is_openedgeswipe": false,
"paymentmethod_update_user_id": 1,
"paymentmethod_insert_user_id": 1,
"paymentmethod_insertdate": "2014-10-07 14:53:16",
"paymentmethod_deleted": false,
"paymentmethod_is_mobile_visible": true
}
]
}
The wrapper class I'm using is called Table.
data class Table<T>(
@SerializedName("Table") val models : Array<T>
)
The actual model class is PaymentMethod.
data class PaymentMethod(
@SerializedName("paymentmethod_id") val idNumber : Int = -1
)
I have created a generic data manager class that takes < T > type. I think use subclasses of the data manager to localize the input and results (such as declaring the model class PaymentMethod.
open class NXDataManager<T>(manager: NXNetworkManager? = null, rpc : String?, parameters: List<Pair<String, String>>? = null, method : String = "get")
{
...
open fun sendRequest(completionHandler: (models:Array<T>) -> Unit, errorHandler: (error:FuelError) -> Unit) {
val request = NXNetworkRequest(rpc, parameters, method)
request.send(manager, completionHandler = { s: String ->
val table: Table<T> = Gson().fromJson(s)
completionHandler(table.models)
}, errorHandler = errorHandler)
}
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
}
My subclassed data manager specifies the model to parse into.
final public class PaymentMethodsDataManager : NXDataManager<PaymentMethod>
{
constructor () : super("genGetPaymentMethods")
}
When I run the code as:
val table: Table<T> = Gson().fromJson(s)
I get an error message java.lang.ClassCastException: java.lang.Object[] cannot be cast to Networking.PaymentMethod[]. However, when I pass in an explicit type it works as expected--parsing the array into PaymentMethod models:
val table: Table<PaymentMethod> = Gson().fromJson(s)
Any ideas of how I can still use the generic type T?
Data Class :
data class Table<T>(
@SerializedName("Table") val models : Array<T>
)
to JSON:
val gson = Gson()
val json = gson.toJson(table)
from JSON:
val json = getJson()
val table = gson.fromJson(json, Table::class.java)
Method fromJson
is generic, so when you call it for Table<T>
variable it creates Array<Any>
as most suitable. You need to notice that PaymentMethod
class extends T
generic, but I don't know is it even possible. If you find out how to make it, use something like following:
val table: Table<T> = Gson().fromJson<Table<PaymentMethod>>(s)
In your case I'm using gson adapters. Following function creates object with specified type
parameter:
fun getObjectFromString(type: Type, string: String) =
Gson().getAdapter(TypeToken.get(type)).fromJson(string)
To use it write something following:
val table: Table<T> = getObjectFromString(Table<PaymentMethod>::class.java, s) as Table<PaymentMethod>
Update
To avoid spare class cast you can use reified
generic function:
inline fun <reified T> getObjectFromString(string: String): T =
getGsonConverter().getAdapter(TypeToken.get(T::class.java)).fromJson(string)!!
In that case using would be easier:
val table: Table<T> = getObjectFromString<Table<PaymentMethod>>(s)
I used first solution in cases where I don't know what type the object would be - I've got only Type
variable with information about that object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With