You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Gson TypeAdapter反序列化数组时未被调用的问题咨询

问题原因与解决方案

你猜的没错!问题确实出在你反序列化的是**MyObject[]数组类型**,但你只注册了单个MyObjectTypeAdapter——Gson不会自动将单个类型的适配器应用到它的数组/集合类型上,这就是你的断点和日志都没触发的核心原因。

下面给你两种可行的解决思路,同时修复MyTypeAdapter本身的关键问题:

1. 直接注册数组类型的TypeAdapter

既然目标是反序列化MyObject[],那直接给数组类型注册适配器即可:

val gson = GsonBuilder()
    // 用TypeToken明确指定MyObject数组类型,注册对应适配器
    .registerTypeAdapter(
        object : TypeToken<MyObject[]>() {}.type,
        MyTypeAdapter().nullSafe() // nullSafe()帮你自动处理数组中的null元素
    )
    .create()

// 执行反序列化
val myObjects = gson.fromJson(inputJson, MyObject::class.java)

2. 更灵活的方案:用TypeAdapterFactory覆盖所有MyObject相关类型

如果之后你还需要反序列化单个MyObject或者List<MyObject>这类集合,用TypeAdapterFactory会更省心——它会自动匹配所有涉及MyObject的类型:

// 自定义TypeAdapterFactory
class MyTypeAdapterFactory : TypeAdapterFactory {
    override fun <T : Any?> create(gson: Gson, typeToken: TypeToken<T>): TypeAdapter<T>? {
        // 匹配MyObject类型(包括单个实例、数组元素、集合元素)
        return if (typeToken.rawType == MyObject::class.java) {
            MyTypeAdapter().nullSafe() as TypeAdapter<T>
        } else {
            null // 不处理其他无关类型
        }
    }
}

// 注册Factory并执行反序列化
val gson = GsonBuilder()
    .registerTypeAdapterFactory(MyTypeAdapterFactory())
    .create()
val myObjects = gson.fromJson(inputJson, MyObject[].class)

关键修复:MyTypeAdapter的实现问题

你的MyTypeAdapter里有个严重的逻辑漏洞:每次调用read/write时都新建Gson()实例,这会完全绕开你自定义的配置,甚至可能导致循环反序列化。正确的做法是手动解析/写入JSON字段,而不是依赖默认Gson实例:

class MyTypeAdapter : TypeAdapter<MyObject>() {
    override fun write(out: JsonWriter, myObject: MyObject) {
        out.beginObject()
        // 逐个写入对象字段
        out.name("id").value(myObject.id)
        out.name("name").value(myObject.name)
        out.name("description").value(myObject.description)
        // 序列化others数组,复用Gson内置的集合适配器
        out.name("others")
        Gson().toJson(myObject.others, object : TypeToken<List<Map<String, String>>>() {}.type, out)
        out.endObject()
    }

    override fun read(`in`: JsonReader): MyObject {
        Log.d("MyTypeAdapter", "Deserialization via custom TypeAdapter")
        var id: String? = null
        var name: String? = null
        var description: String? = null
        var others: List<Map<String, String>> = emptyList()

        `in`.beginObject()
        // 逐个读取JSON字段
        while (`in`.hasNext()) {
            when (`in`.nextName()) {
                "id" -> id = `in`.nextString()
                "name" -> name = `in`.nextString()
                "description" -> description = `in`.nextString()
                "others" -> others = Gson().fromJson(`in`, object : TypeToken<List<Map<String, String>>>() {}.type)
                else -> `in`.skipValue() // 跳过未知字段,避免解析失败
            }
        }
        `in`.endObject()

        // 根据业务逻辑确保必填字段非空,这里用requireNotNull示例
        return MyObject(
            requireNotNull(id),
            requireNotNull(name),
            requireNotNull(description),
            others
        )
    }
}

这样修改后,你的自定义适配器就能正常触发,并且正确调用父类构造器初始化MyObject了。


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

火山引擎 最新活动