在一个函数中解码不同的对象

问题描述 投票:0回答:1

登录响应

{
    "data": {
        "Token": "4F5696"
    },
    "success": true,
    "message": null
}

游戏菜单响应

    "data": {
        "GameMenuModels":[{"mobileApiProductMenus": 
        ...
    },
    "success": true,
    "message": null

这是不同的 json 响应,它们都有

"data"
"success"
"message"

所以我添加了一个基本响应

class BaseResponse<T>(
    @SerializedName("success") var success: Boolean = false,
    @SerializedName("message") var message: String? = "",
    @SerializedName("data") var data: T? = null
)

单独解析jsonString即可成功。

val baseType = object : TypeToken<BaseResponse<LogonResponse>>() {}.type
val logonResponse = Gson().fromJson<BaseResponse<LogonResponse>>(jsonString, baseType)
//parse logon success
val baseType = object : TypeToken<BaseResponse<GameMenuResponse>>() {}.type
val logonResponse = Gson().fromJson<BaseResponse<GameMenuResponse>>(jsonString, baseType)
//parse GameMenu success

但是如果我在通用函数中解码

fun <T> decode(jsonString: String): BaseMSResponse<T> {
    val baseMsType = object : TypeToken<BaseMSResponse<T>>() {}.type
    return Gson().fromJson(jsonString, baseMsType)
}
val logonResponse = decode<LogonResponse>(jsonString) //crash
val gameMenuResponse = decode(jsonString) //crash

错误日志:java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap无法转换

如何解决?

TypeToken
可以用泛型解析对象吗?

android json kotlin generics retrofit
1个回答
0
投票

正如我上面回答的那样,我建议在这种情况下使用继承而不是泛型,因为它很容易维护。如果您想引入一种具有新字段的新型响应,那么您必须用它更新基类。

这是您的继承案例的代码,对于反序列化,我使用 Jackson 库而不是 Gson:

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue

fun main() {
    val mapper = jacksonObjectMapper()

    val logonResponse = mapper.readValue<LogonResponse>(logonResponse)
    val gameMenuResponse = mapper.readValue<GameMenuResponse>(gameMenuResponse)
}

open class BaseResponse(
    @JsonProperty
    val success: Boolean = false,

    @JsonProperty
    val message: String? = "",
)

class LogonResponse(
    val data: TokenData
) : BaseResponse()

class TokenData(
    @JsonProperty("Token")
    val token: String
)

class GameMenuResponse(
    val data: GameMenuModelWrapper
) : BaseResponse()

class GameMenuModelWrapper(
    @JsonProperty("GameMenuModels")
    val models: List<GameMenuModel>
)


data class GameMenuModel(val mobileApiProductMenus: String?)

val logonResponse = """
        {
            "data": {
                "Token": "4F5696"
            },
            "success": true,
            "message": "ABC"
        }
    """.trimIndent()

val gameMenuResponse = """
        {
            "data": {
                "GameMenuModels":[
                    {
                        "mobileApiProductMenus": "Some Menu Here"
                    }
                ]
            },
            "success": false,
            "message": "XYZ"
        }
    """.trimIndent()
© www.soinside.com 2019 - 2024. All rights reserved.