You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:31:11