【问题标题】:Kotlin Gson DeserializingKotlin Gson 反序列化
【发布时间】:2017-12-22 16:41:33
【问题描述】:

我收到一个带有地图包装器的 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
)

我创建了一个采用 类型的通用数据管理器类。我认为使用数据管理器的子类来本地化输入和结果(例如声明模型类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[] cannot be cast to Networking.PaymentMethod[]。但是,当我传入显式类型时,它会按预期工作——将数组解析为 PaymentMethod 模型:

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

关于如何仍然使用泛型类型 T 的任何想法?

【问题讨论】:

    标签: android kotlin gson


    【解决方案1】:

    数据类:

    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)
    

    【讨论】:

    • 我无法使用 Table::class.java,因为 Table 需要指定其泛型类型 Table::class.java。但这会引发错误,因为我猜编译器在编译时无法判断 T 是什么(这不是泛型的初衷吗?)。
    【解决方案2】:

    方法fromJson 是通用的,因此当您为Table&lt;T&gt; 变量调用它时,它会创建最合适的Array&lt;Any&gt;。您需要注意 PaymentMethod 类扩展了 T 泛型,但我不知道它是否可能。如果您知道如何制作,请使用以下内容:

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

    在您的情况下,我使用的是 gson 适配器。以下函数使用指定的type 参数创建对象:

    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 变量,其中包含有关该对象的信息。

    【讨论】:

      【解决方案3】:

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

      创建一个data classPaymentMethod

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

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多