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

Gson支持toString格式而非JSON语法的原理及日期字段问题咨询

Gson解析非标准格式字符串的问题解答

我来帮你拆解这两个问题,刚好对Gson的这个“隐藏”特性比较熟悉:

1. Gson为何支持{a=5, b=field}这种非标准格式?

这其实是Gson**宽松解析(Lenient Mode)**的兼容特性——默认情况下,Gson创建的实例会自动开启宽松模式,它会容忍很多不符合JSON官方标准的写法,包括:

  • 用等号=代替冒号:分隔键值对
  • 键名不包裹双引号
  • 用单引号代替双引号包裹字符串
  • 允许对象末尾多出来的逗号

官方文档没特意大篇幅讲这个,因为这属于边缘兼容场景,主要是为了适配Java实体类默认的toString()输出(很多类的toString就是{key=value, ...}这种格式),方便开发者在调试、快速转换时不用严格写标准JSON。

你可以试试关闭宽松模式,这时候再解析这种格式就会直接报错:

JsonReader reader = new JsonReader(new StringReader(json2));
reader.setLenient(false); // 关闭宽松模式
Pojo obj = gsonInstance.fromJson(reader, Pojo.class); // 抛出JsonSyntaxException

2. 如何解决toString格式下的日期字段解析问题?

当字段值里有冒号(比如日期2024-05-20 12:34:56)时,Gson的宽松解析会彻底混乱——它会把值里的冒号当成键值分隔符,导致无法正确识别字段值的边界。这里有两个实用的解决方案:

方案一:转成标准JSON再解析(简单高效)

用正则把非标准格式转换为符合规范的JSON,核心是给键加双引号、把等号换成冒号、给字符串类型的值(包括日期)加双引号,同时保留数字的原始格式:

String nonStandardStr = "{a=5, b=field, date=2024-05-20 12:34:56}";

// 第一步:给键加双引号,替换等号为冒号
String temp = nonStandardStr.replaceAll("(\\w+)=", "\"$1\":");
// 第二步:给非数字的字段值加双引号
String standardJson = temp.replaceAll(":([^,}\\d]+)", ":\"$1\"");

// 现在standardJson是标准JSON:{"a":5, "b":"field", "date":"2024-05-20 12:34:56"}
Pojo obj = gsonInstance.fromJson(standardJson, Pojo.class);

这个方案适合字段值没有特殊符号(比如逗号、等号)的场景,对于固定格式的日期完全够用。

方案二:自定义TypeAdapter(灵活通用)

如果你的字段值可能包含逗号、等号这类特殊字符,正则就hold不住了,这时候可以写一个自定义的TypeAdapter手动解析:

public class PojoTypeAdapter extends TypeAdapter<Pojo> {
    @Override
    public void write(JsonWriter out, Pojo value) throws IOException {
        // 如果不需要序列化,直接抛出异常或留空
        throw new UnsupportedOperationException("序列化功能未实现");
    }

    @Override
    public Pojo read(JsonReader in) throws IOException {
        in.beginObject();
        Pojo.PojoBuilder builder = Pojo.builder();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        
        while (in.hasNext()) {
            String key = in.nextName();
            String value = in.nextString();
            
            switch (key) {
                case "a":
                    builder.a(Integer.parseInt(value));
                    break;
                case "b":
                    builder.b(value);
                    break;
                case "date":
                    // 解析日期字段
                    LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
                    builder.date(Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()));
                    break;
            }
        }
        in.endObject();
        return builder.build();
    }
}

然后把这个适配器注册到Gson实例中:

Gson gsonInstance = new GsonBuilder()
        .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
        .registerTypeAdapter(Pojo.class, new PojoTypeAdapter())
        .create();

这种方法能处理各种复杂的非标准格式,适合需要长期维护的业务场景。


内容的提问来源于stack exchange,提问作者nikel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:12:53