使用Gson转换HashMap<LocalDate,Int>与JSON:反向转换失败原因
问题原因解析
你遇到的问题核心在于JSON对象的键只能是字符串,而Gson默认没有内置逻辑,能把JSON里的日期字符串键自动转换成LocalDate类型。
当序列化Map<LocalDate, Int>时,Gson会自动把LocalDate转为字符串形式(比如"2024-01-01")作为JSON对象的键;但反序列化时,Gson会尝试直接把这个字符串键当成LocalDate实例解析——而LocalDate并非字符串类型,Gson默认的反序列化器不知道如何将字符串转换为LocalDate作为Map的键,因此抛出Expected BEGIN_OBJECT but was STRING异常(它原本期望解析一个LocalDate的JSON对象,结果拿到的是字符串)。
解决方法
方法1:注册Java 8日期适配器(推荐)
如果项目使用Java 8+日期API,Gson提供了专门的扩展库处理这类类型:
- 引入Gradle依赖:
implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.code.gson:gson-javatype-adapters:2.10.1'
- 创建带适配器的Gson实例:
val gson = GsonBuilder() .registerTypeAdapter(LocalDate::class.java, LocalDateTypeAdapter()) .create()
用这个gson实例即可完成Map<LocalDate, Int>的双向序列化/反序列化。
方法2:自定义TypeAdapter处理Map键转换
若不想引入额外依赖,可自行编写适配器处理LocalDate键的解析:
class LocalDateMapKeyAdapter : TypeAdapter<LocalDate>() { override fun write(out: JsonWriter, value: LocalDate?) { value?.let { out.value(it.toString()) } } override fun read(`in`: JsonReader): LocalDate { return LocalDate.parse(`in`.nextString()) } }
注册到GsonBuilder:
val gson = GsonBuilder() .registerTypeAdapter(LocalDate::class.java, LocalDateMapKeyAdapter()) .create()
这样Gson反序列化Map键时,会通过适配器将字符串转为LocalDate。
关于你的替代方案
你手动遍历JSON对象的键,自行调用LocalDate.parse(key)完成字符串到LocalDate的转换,本质上是替Gson完成了它默认未实现的键类型转换工作,因此可以正常运行。
内容的提问来源于stack exchange,提问作者android developer
相关产品推荐
相关产品推荐

