SpringBoot4.0.0 常用的jackson序列化以及反序列化配置

829 阅读2分钟

前言

由于项目由SpringBoot3.x升级到SpringBoot4.x,内置的jackson2升级为jackson3,包名改变以及部分类已经不再向下兼容,记录下升级过程中的一些问题

统一的序列化配置

SpringBoot3.x中的LocalDateTime序列化以及反序列化配置,如果使用的是Jackson2ObjectMapperBuilderCustomizer的话,由于该类在jackson3中已经不存在,需要改为使用jackson3中JsonMapperBuilderCustomizer的方式,并且写法略有改变

问题点

  1. 前后端请求中,时间类型的请求响应参数,统一使用 yyyy-MM-dd HH:mm:ss 格式
  2. 由于前端对于后端结果中,Long类型数据的精度缺失,为避免前端处理,统一由后端将Long类型数据序列化为String类型数据返回
  3. 对jackson添加统一的Long类型序列化后,响应类中,无需在Long参数中重复添加@JsonSerialize(using = ToStringSerializer.class)注解

代码示例

import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.JsonParser;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.ValueSerializer;
import tools.jackson.databind.module.SimpleModule;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Configuration
public class JacksonConfig {

    private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);

    @Bean
    public JsonMapperBuilderCustomizer jsonCustomizer() {
        return builder -> {
            // 添加 LocalDateTime 的序列化与反序列化
            builder.addModule(
                    new SimpleModule()
                            // Long 的序列化
                            .addSerializer(Long.class, new LongSerializer())
                            // LocalDateTime 的序列化
                            .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer())
                            // LocalDateTime 的反序列化
                            .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer())
            );
        };
    }

    /**
     * Long 的序列化
     */
    private static class LongSerializer extends ValueSerializer<Long> {
        @Override
        public void serialize(Long value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
            if (value != null) {
                gen.writeString(value.toString());
            }
        }
    }

    /**
     * LocalDateTime 的序列化
     */
    private static class LocalDateTimeSerializer extends ValueSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {
            if (value != null) {
                gen.writeString(value.format(DATE_TIME_FORMATTER));
            } else {
                gen.writeNull();
            }
        }
    }

    /**
     * LocalDateTime 的反序列化
     */
    private static class LocalDateTimeDeserializer extends ValueDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException {
            String dateString = p.getString();
            if (dateString == null || dateString.trim().isEmpty()) {
                return null;
            }
            return java.time.LocalDateTime.parse(dateString, DATE_TIME_FORMATTER);
        }
    }
}

部分jackson包名需要替换 com.fasterxml.jackson -> tools.jackson

在 Jackson 3 中,@JsonProperty 注解仍然有效,且核心功能(字段重命名、读写控制、必填校验等)保持不变。

不过需要注意以下细节:

  • 包路径不变:仍为 com.fasterxml.jackson.annotation.JsonProperty,无需修改导入语句。
  • 兼容性保障:Jackson 3 对该注解的支持是完全向后兼容的,基于 Jackson 2 开发的代码中使用 @JsonProperty 的逻辑可直接迁移。
  • 搭配新构建器:若结合 Jackson 3 新的 JsonMapper.Builder 构建 ObjectMapper@JsonProperty 的注解逻辑也会被正常识别和处理。

例如,以下代码在 Jackson 3 中依然能正常工作:

public class User {
    @JsonProperty("user_id")
    private Long id;

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}