Gson TypeAdapter反序列化数组时未被调用的问题咨询
问题原因与解决方案
你猜的没错!问题确实出在你反序列化的是**MyObject[]数组类型**,但你只注册了单个MyObject的TypeAdapter——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




