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
相关产品推荐
相关产品推荐

