登录响应
{
"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
可以用泛型解析对象吗?
正如我上面回答的那样,我建议在这种情况下使用继承而不是泛型,因为它很容易维护。如果您想引入一种具有新字段的新型响应,那么您必须用它更新基类。
这是您的继承案例的代码,对于反序列化,我使用 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()