Kotlin Gson Deserializing

I get a JSON data model that has a map wrapper table. I am trying to use generics to pass in a type that is outside the shell, but it does not translate well at runtime. Here is 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 created a generic data manager class that accepts <T>. I think using subclasses of the data manager to localize input and results (for example, declaring a PaymentMethod model class.

 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 subclass data manager defines a model for analysis.

 final public class PaymentMethodsDataManager : NXDataManager<PaymentMethod> { constructor () : super("genGetPaymentMethods") } 

When I run the code like:

 val table: Table<T> = Gson().fromJson(s) 

I get the error java.lang.ClassCastException: java.lang.Object [] could not be passed to Networking.PaymentMethod [] . However, when I pass an explicit type, it works as expected - parsing the array in PaymentMethod models:

 val table: Table<PaymentMethod> = Gson().fromJson(s) 

Any ideas on how I can use generic type T?

+5
source share
3 answers

Data class:

 data class Table<T>( @SerializedName("Table") val models : Array<T> ) 

in JSON:

 val gson = Gson() val json = gson.toJson(table) 

from JSON:

 val json = getJson() val table = gson.fromJson(json, Table::class.java) 
+4
source

fromJson is a generic method, so when you call it on the Table<T> variable, it creates an Array<Any> as the most appropriate. You should notice that the PaymentMethod class extends T generic, but I don't know if this is possible. If you learn how to do this, use something like the following:

 val table: Table<T> = Gson().fromJson<Table<PaymentMethod>>(s) 

In your case, I use gson adapters. The following function creates an object with the specified type parameter:

 fun getObjectFromString(type: Type, string: String) = Gson().getAdapter(TypeToken.get(type)).fromJson(string) 

To use it, write the following:

 val table: Table<T> = getObjectFromString(Table<PaymentMethod>::class.java, s) as Table<PaymentMethod> 

Update

To avoid creating a reified class, you can use the reified generic function:

 inline fun <reified T> getObjectFromString(string: String): T = getGsonConverter().getAdapter(TypeToken.get(T::class.java)).fromJson(string)!! 

In this case, the use will be easier:

 val table: Table<T> = getObjectFromString<Table<PaymentMethod>>(s) 

I used the first solution in cases where I do not know what the type of the object will be. I only have a type variable with information about this object.

+3
source

java.lang.ClassCastException: java.lang.Object [] cannot be dropped Networking.PaymentMethod []

Your json

 { "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 } ] } 

Create a data class , PaymentMethod .

We often create classes whose main purpose is data storage. In this class, some standard functions and utility functions are often mechanically derived from data.

 data class PaymentMethod(@SerializedName("Table") val table:ArrayList<PaymentData> ) data class PaymentData ( @SerializedName("paymentmethod_id") val paymentmethod_id: Int, @SerializedName("paymentmethod_description") val paymentmethod_description: String, @SerializedName("paymentmethod_code") val paymentmethod_code:String, @SerializedName("paymentmethod_is_ach_onfile") val paidStatus:Boolean, @SerializedName("paymentmethod_is_element") val paymentmethod_is_element:Boolean, @SerializedName("paymentmethod_is_reward") val paymentmethod_is_reward:Boolean, @SerializedName("paymentmethod_is_openedgeswipe") val paymentmethod_is_openedgeswipe:Boolean, @SerializedName("paymentmethod_update_user_id") val paymentmethod_update_user_id:Int, @SerializedName("paymentmethod_insert_user_id") val paymentmethod_insert_user_id:Int, @SerializedName("paymentmethod_insertdate") val paymentmethod_insertdate:String, @SerializedName("paymentmethod_deleted") val paymentmethod_deleted:Boolean), @SerializedName("paymentmethod_is_mobile_visible") val paymentmethod_is_mobile_visible:Boolean ) 

You can call this way

  val paymentDATA = Gson().fromJson<PaymentMethod>("JSON_RESPONSE", PaymentMethod::class.java) val _adapterPaymentHistory = paymentDATA.table 
+2
source

Source: https://habr.com/ru/post/1274280/


All Articles