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

Jackson自定义JsonSerializer多字段拼接及反序列化问题

解决方案:Jackson自定义DatePair序列化/反序列化

针对遇到的四个问题,逐一解决如下:

1. 解决序列化Model1的异常 & 实现日期不带引号的格式

异常原因:使用writeRaw直接输出非JSON标准值的内容,破坏了对象内部的JSON结构(对象字段值必须是合法JSON类型:字符串、数字、对象等)。
解决方法:将DatePair序列化为单个字符串值,用gen.writeString()替代writeRaw,同时手动格式化日期为无引号的字符串后拼接。

2. 让@JsonFormat作用于DatePair的日期字段

问题原因:全局序列化器默认无法读取父对象字段上的@JsonFormat注解。
解决方法:通过SerializerProvider获取当前字段的注解配置,动态选择日期格式化规则(优先使用注解配置,无注解时用全局默认)。

修改后的序列化器

public static class DatePairJsonSerializer extends JsonSerializer<DatePair> {
    @Override
    public void serialize(DatePair value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 获取当前字段的@JsonFormat注解
        JsonFormat format = serializers.getAnnotationIntrospector().findFormat(serializers.getContextualType());
        
        // 初始化日期格式化器
        SimpleDateFormat dateFormat;
        if (format != null) {
            dateFormat = new SimpleDateFormat(format.pattern());
            dateFormat.setTimeZone(TimeZone.getTimeZone(format.timezone()));
        } else {
            dateFormat = (SimpleDateFormat) serializers.getDateFormat();
        }

        // 格式化日期并拼接目标字符串
        String date1Str = dateFormat.format(value.getDate1());
        String date2Str = dateFormat.format(value.getDate2());
        String serializedStr = String.format("(%s, %s)", date1Str, date2Str);
        
        // 写入合法的JSON字符串值
        gen.writeString(serializedStr);
    }
}

3. 匹配的反序列化器实现

将形如"(2025/06/22 10:02:48.000, 2025/06/22 10:02:48.000)"的字符串解析为DatePair:

public static class DatePairJsonDeserializer extends JsonDeserializer<DatePair> {
    @Override
    public DatePair deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String rawValue = p.getText();
        // 清理字符串:去除首尾括号和多余空格
        String cleaned = rawValue.replaceAll("^\\(|\\)$", "").trim();
        String[] dateSegments = cleaned.split(",\\s*");
        
        // 获取字段上的@JsonFormat注解配置
        JsonFormat format = ctxt.getAnnotationIntrospector().findFormat(ctxt.getContextualType());
        SimpleDateFormat dateFormat;
        if (format != null) {
            dateFormat = new SimpleDateFormat(format.pattern());
            dateFormat.setTimeZone(TimeZone.getTimeZone(format.timezone()));
        } else {
            dateFormat = (SimpleDateFormat) ctxt.getDateFormat();
        }

        DatePair datePair = new DatePair();
        try {
            datePair.setDate1(dateFormat.parse(dateSegments[0]));
            datePair.setDate2(dateFormat.parse(dateSegments[1]));
        } catch (ParseException e) {
            throw new IOException("Failed to parse DatePair string: " + rawValue, e);
        }
        return datePair;
    }
}

注册反序列化器

在main方法中添加反序列化器到Module:

// 原有的序列化器注册后,添加反序列化器
simpleModule.addDeserializer(DatePair.class, new DatePairJsonDeserializer());

测试结果

  • 单独序列化DatePair:输出"(2025-06-22 10:02:48, 2025-06-22 10:02:48)"(合法JSON字符串,日期无引号)
  • 序列化Model1:输出{"datePair":"(2025/06/22 10:02:48.000, 2025/06/22 10:02:48.000)"}(@JsonFormat的格式和时区生效)
  • 反序列化:可将上述JSON字符串正确解析为DatePair对象

关键注意事项

  • 必须保证生成的JSON结构合法:DatePair必须作为字符串值存在,不能输出裸的括号内容
  • 通过注解 introspector 获取字段级的格式配置,实现灵活的格式化规则切换
  • 反序列化时要处理字符串解析异常,提升代码鲁棒性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 19:54:51