Kotlin Gson 反序列化

9

我收到一个带有map包装器Table的JSON数据模型。我正在尝试使用泛型来传递超出包装器范围的类型,但在运行时无法正确转换。下面是我的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
   }
  ]
}

我使用的包装类被称为Table。
data class Table<T>(
    @SerializedName("Table") val models : Array<T>
)

实际的模型类是PaymentMethod。
data class PaymentMethod(
    @SerializedName("paymentmethod_id") val idNumber : Int = -1
)

我创建了一个通用的数据管理器类,它接受 < T > 类型。我认为使用数据管理器的子类来本地化输入和结果是可行的(例如声明模型类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)

}

我的子类数据管理器指定要解析的模型。

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

}

当我运行以下代码时:
val table: Table<T> = Gson().fromJson(s)

我收到了一个错误信息java.lang.ClassCastException: java.lang.Object[] 无法转换为 Networking.PaymentMethod[]。然而,当我传入明确的类型时,它按预期工作--将数组解析为PaymentMethod模型:

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

有什么办法可以继续使用通用类型T吗?
3个回答

12

数据类:

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

转换为JSON:

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

来自JSON:

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

1
我无法使用Table::class.java,因为Table需要指定其泛型类型Table<T>::class.java。但是这会导致错误,因为我猜测编译器在编译时无法确定T是什么(这不是泛型的首要目的吗?)。 - Hobbes the Tige

4

方法fromJson是通用的,因此当您为Table<T>变量调用它时,它会创建Array<Any>作为最合适的类型。需要注意的是,PaymentMethod类扩展了T泛型,但我不知道是否可能。如果您找到如何实现它的方法,请使用以下类似的语句:

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

在您的情况下,我将使用gson适配器。以下函数将创建具有指定类型参数的对象:

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

使用它需要编写以下内容:

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

更新

为了避免无用的类转换,您可以使用reified泛型函数:

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

在这种情况下,使用会更容易:

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

在我不知道对象类型的情况下,我使用了第一种解决方案——我只有一个包含该对象信息的Type变量。


2

java.lang.ClassCastException: java.lang.Object[] 无法转换为 Networking.PaymentMethod[]

您的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
   }
  ]
}

创建一个名为PaymentMethoddata class

我们经常创建用于保存数据的类。在这样的类中,一些标准功能和实用函数通常可以从数据中机械地推导出来。

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
                       )

您可以这样调用。
  val paymentDATA = Gson().fromJson<PaymentMethod>("JSON_RESPONSE", PaymentMethod::class.java)
  val _adapterPaymentHistory = paymentDATA.table

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接