You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Gson解析Kotlin stdlib.Result类型时访问值抛出ClassCastException

问题原因
  • 核心问题是Kotlin标准库的Result<T>属于值类(value class),Gson作为Java生态的序列化框架,对Kotlin特有的值类支持不完善,无法将TypeToken<Result<SomeObject>>携带的泛型信息正确传递到Result内部持有的value字段上,因此会默认将JSON对象解析为LinkedTreeMap类型存储在Result内部。
  • 调试时能看到完整值是因为调试器仅读取Result内部的原始存储值,不会触发类型转换逻辑;只有当你调用onSuccess、getOrNull等需要返回SomeObject类型的方法时,才会执行隐式的强转操作,此时就会抛出类型不匹配异常。
解决方案

方案1(更简单,推荐):先解析目标类型再手动包装为Result

跳过直接解析Result的步骤,先把JSON解析为实际业务类型SomeObject,再用Kotlin标准库方法手动包装为Result,完全规避Gson对Result类型的适配问题:

val result = runCatching {
    gson.fromJson(jsonString, SomeObject::class.java)
}
// 原有逻辑完全不用改
assertTrue(result.isSuccess)
result.onSuccess {
    println(it)
}

如果要兼容JSON解析成功但业务层面需要返回Failure的场景,也可以自行判断后调用Result.success()或Result.failure()手动封装。

方案2:自定义Result类型的Gson TypeAdapter

如果确实需要直接反序列化为Result<T>类型,可以自定义TypeAdapter实现适配,手动处理泛型参数的解析逻辑:

class ResultTypeAdapter<T>(private val dataType: Type) : TypeAdapter<Result<T>>() {
    override fun write(writer: JsonWriter, value: Result<T>?) {
        // 按需实现序列化逻辑
    }

    override fun read(reader: JsonReader): Result<T> {
        return try {
            val value = Gson().fromJson<T>(reader, dataType)
            Result.success(value)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

// 注册Adapter后使用
val gson = GsonBuilder()
    .registerTypeAdapterFactory { gson, type ->
        if (type.rawType != Result::class.java) return@registerTypeAdapterFactory null
        val actualType = (type.type as ParameterizedType).actualTypeArguments[0]
        ResultTypeAdapter<Any>(actualType) as TypeAdapter<*>
    }
    .create()

内容的提问来源于stack exchange,提问作者zhaider

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 17:24:02