Gson无法反序列化自身生成的JSON字符串?Kotlin数据类HashMap问题
Gson 默认处理 Map 的自定义类型 Key 时,不会把 Key 对象序列化为 JSON 对象,而是直接调用对象的 toString() 方法生成字符串作为 JSON 的 Key。你生成的 JSON 里,Key 是 Picture 实例的字符串表示(比如 Picture(image_url=...)),反序列化时 Gson 尝试把这个字符串解析成 Picture 对象,自然会抛出 Expected BEGIN_OBJECT but was STRING 异常——因为它期待的是 {...} 格式的 JSON 对象,结果拿到的是普通字符串。
方案1:自定义 TypeAdapter + 开启复杂 Map Key 序列化
给 Picture 类写一个自定义的 TypeAdapter,让 Gson 把 Key 序列化为结构化的 JSON 字符串,反序列化时再把这个字符串转回 Picture 对象,同时要开启 Gson 的复杂 Map Key 序列化支持:
首先定义你的 Picture 数据类(示例):
data class Picture( val image_url: String, val creator_name: String, val creator_address: String, val image_name: String, val additional_url: String )
然后编写 TypeAdapter:
class PictureKeyTypeAdapter : TypeAdapter<Picture>() { private val internalGson = Gson() override fun write(writer: JsonWriter, picture: Picture) { // 将Picture转为JSON字符串作为Key,Gson会自动处理转义 val pictureJson = internalGson.toJson(picture) writer.value(pictureJson) } override fun read(reader: JsonReader): Picture { // 读取Key对应的JSON字符串,再转回Picture对象 val pictureJson = reader.nextString() return internalGson.fromJson(pictureJson, Picture::class.java) } }
创建 Gson 实例时注册适配器并开启复杂 Key 序列化:
val gson = GsonBuilder() .registerTypeAdapter(Picture::class.java, PictureKeyTypeAdapter()) .enableComplexMapKeySerialization() .create()
用这个 Gson 实例序列化/反序列化你的 HashMap<Picture, String>,就能正常工作了。
方案2:将 Map 转为 List 处理
如果不想写自定义适配器,可以把 HashMap 转成 List<Pair<Picture, String>>,Gson 对这种结构的序列化和反序列化支持更友好:
// 序列化 val map = HashMap<Picture, String>() // ... 填充map数据 val list = map.toList() val json = gson.toJson(list) // 反序列化 val type = object : TypeToken<List<Pair<Picture, String>>>() {}.type val list = gson.fromJson<List<Pair<Picture, String>>>(json, type) val restoredMap = list.toMap()
方案3:改用唯一字符串作为 Map Key
如果 Picture 里有唯一标识字段(比如 image_url),可以直接用这个字符串作为 Map 的 Key,完全避开自定义对象作为 Key 的问题:
val map = HashMap<String, String>() map[picture.image_url] = yourBase64String // 序列化和反序列化都能正常工作,无需额外配置
内容的提问来源于stack exchange,提问作者Markusbug

