GSON序列化LocalDate为JSON对象异常:Expected BEGIN_OBJECT but was STRING
解决Gson序列化LocalDate为JSON对象的问题
我有一个ObjectClass类,包含java.time.LocalDate类型的dateField字段,使用Gson的toJson方法序列化后,该字段会变成字符串格式(如"2024-06-10"),但实际需要将其序列化为包含year、month、day的JSON对象。之前尝试使用自定义Adapter但未生效,导致其他应用解析时抛出异常:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 14 column 17 path $.dateField; nested exception is com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 14 column 17 path $.dateField
期望输出格式:
{"id":"03339302020230232020","refnumber":"89132C28C756DC","source":"SSS","dateField":{"year":2024,"month":6,"day":10}}
1. 编写正确的LocalDate自定义TypeAdapter
实现TypeAdapter<LocalDate>,序列化时将LocalDate转换为包含年、月、日的JsonObject,同时支持反序列化(如果需要):
import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.time.LocalDate; public class LocalDateAdapter extends TypeAdapter<LocalDate> { @Override public void write(JsonWriter out, LocalDate value) throws IOException { if (value == null) { out.nullValue(); return; } out.beginObject(); out.name("year").value(value.getYear()); out.name("month").value(value.getMonthValue()); out.name("day").value(value.getDayOfMonth()); out.endObject(); } @Override public LocalDate read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } in.beginObject(); int year = 0, month = 0, day = 0; while (in.hasNext()) { switch (in.nextName()) { case "year": year = in.nextInt(); break; case "month": month = in.nextInt(); break; case "day": day = in.nextInt(); break; default: in.skipValue(); break; } } in.endObject(); return LocalDate.of(year, month, day); } }
2. 正确注册TypeAdapter到GsonBuilder
自定义Adapter未生效大多是注册方式错误,需在构建Gson实例时明确注册并覆盖默认的LocalDate处理逻辑:
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.time.LocalDate; public class Main { public static void main(String[] args) { ObjectClass obj = new ObjectClass(); obj.setId("03339302020230232020"); obj.setRefnumber("89132C28C756DC"); obj.setSource("SSS"); obj.setDateField(LocalDate.of(2024, 6, 10)); // 注册自定义Adapter并构建Gson实例 Gson gson = new GsonBuilder() .registerTypeAdapter(LocalDate.class, new LocalDateAdapter()) .create(); String json = gson.toJson(obj); System.out.println(json); } } // ObjectClass类示例 class ObjectClass { private String id; private String refnumber; private String source; private LocalDate dateField; // getter和setter方法 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getRefnumber() { return refnumber; } public void setRefnumber(String refnumber) { this.refnumber = refnumber; } public String getSource() { return source; } public void setSource(String source) { this.source = source; } public LocalDate getDateField() { return dateField; } public void setDateField(LocalDate dateField) { this.dateField = dateField; } }
3. 排查Adapter未生效的常见原因
- 注册顺序问题:若同时注册多个相关Adapter/Factory,确保自定义Adapter最后注册,避免被其他实现覆盖
- 依赖冲突:检查是否引入了
gson-javatime-extensions这类扩展库,其自带的LocalDate Adapter会覆盖自定义实现,需排除依赖或调整注册优先级 - 字段访问权限:确保
ObjectClass的dateField字段为public,或提供对应的getter方法,Gson默认需要能访问到字段才能序列化
内容的提问来源于stack exchange,提问作者user2868864
相关产品推荐
相关产品推荐

