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

Jackson版本升级后com.google.protobuf.Timestamp JSON格式恢复配置咨询

如何在Jackson 2.12.6中恢复Protobuf Timestamp的旧序列化格式

问题背景

Jackson 2.12.6版本对com.google.protobuf.Timestamp类型的JSON序列化行为做了变更:

  • 2.11.3及更早版本:将Timestamp序列化为包含nano和epochSecond字段的对象:
    "date": {
      "nano": 0,
      "epochSecond": 100000
    }
    
  • 2.12.6版本:默认将Timestamp序列化为数字形式的秒级时间戳:
    "date": 100000
    

对应的Proto定义:

syntax = "proto3";

import "google/protobuf/timestamp.proto";

message TopupInfo {
    google.protobuf.Timestamp TopupDate = 3;
}

测试代码示例(验证旧格式的断言会在2.12.6中失败):

package ru.home;

import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.json.JacksonTester;
import ru.home.proto.TopupInfo;
import static org.assertj.core.api.Assertions.assertThat;

public class SampleTest {

    public static final int TOPUP_DATE = 100_000_000;

    private JacksonTester<TopupInfo> json;

    @BeforeEach
    public void makeATestObject() {
        var objectMapper = new ObjectMapper();
        JacksonTester.initFields(this, objectMapper);
    }

    private TopupInfo makeTopupInfo() {
        long millis = TOPUP_DATE;
        var topupInfo = TopupInfo.newBuilder()
                 .setTopupDate(
                   com.google.protobuf.Timestamp.newBuilder()
                                                .setSeconds(millis / 1000)
                                                .setNanos((int) ((millis % 1000) * 1000000))
                                                .build());

        return topupInfo.build();
    }

    @Test
    public void checkFormat() throws IOException {
        assertThat(json.write(makeTopupInfo()))
                .extracting("topupDate")
                .hasFieldOrPropertyWithValue("epochSecond", TOPUP_DATE / 1000);
    }
}

解决方案

要恢复2.11.3版本的序列化格式,最可靠的方式是自定义Timestamp的序列化器,并配置Jackson使用该序列化器:

1. 实现自定义序列化器

创建一个序列化器,将Timestamp序列化为包含nano和epochSecond的JSON对象:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.google.protobuf.Timestamp;
import java.io.IOException;

public class LegacyTimestampSerializer extends JsonSerializer<Timestamp> {
    @Override
    public void serialize(Timestamp value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeNumberField("nano", value.getNanos());
        gen.writeNumberField("epochSecond", value.getSeconds());
        gen.writeEndObject();
    }
}

2. 配置ObjectMapper使用自定义序列化器

在初始化ObjectMapper时,注册Protobuf模块并绑定自定义序列化器:

@BeforeEach
public void makeATestObject() {
    var objectMapper = new ObjectMapper();
    // 注册Jackson Protobuf模块(必须步骤)
    objectMapper.registerModule(new ProtobufModule());
    // 为Timestamp类型配置自定义序列化器
    objectMapper.configOverride(Timestamp.class)
        .setSerializer(new LegacyTimestampSerializer());
    JacksonTester.initFields(this, objectMapper);
}

3. 验证效果

修改后的测试代码会成功通过断言,因为topupDate会被序列化为包含nano和epochSecond的对象,与2.11.3版本的行为一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:01:21