Spring Boot 如何自定义 Jackson JsonMapper 调整 JSON 序列化行为?
2026/9/9 22:41:36 网站建设 项目流程

Spring Boot 如何自定义 Jackson JsonMapper 调整 JSON 序列化行为?

【免费下载链接】spring-bootSpring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.项目地址: https://gitcode.com/gh_mirrors/sp/spring-boot

如果你的 Spring Boot 应用使用 Jackson 3 序列化 JSON(任何@RestController在 Jackson 3 位于 classpath 上时默认就渲染 JSON 响应),你可能需要调整自动配置的tools.jackson.databind.json.JsonMapper:开启缩进输出、控制空值属性是否包含、注册自定义序列化器,甚至彻底替换默认的 Mapper。Spring Boot 提供了从环境属性到 Bean 定制、再到完全替换的多个层次的控制点,本文按从轻到重的顺序说明每条路径,并给出文档中示例代码的写法。

前提:应用中存在自动配置的JsonMapper。只要 Jackson 3 在 classpath 上,Spring Boot 就会自动配置tools.jackson.databind.json.JsonMapperBean,它包含在spring-boot-starter-json中。注意:Jackson 2 的支持已弃用,仅在从 Jackson 2 迁移时保留,长期项目不应依赖它(Jackson 2 走spring.jackson2.*属性和Jackson2ObjectMapperBuilderCustomizer,与本文的 Jackson 3 路径不同)。

通过 spring.jackson.* 环境属性调整序列化行为

最轻量的方式是直接用环境属性配置JsonMapper。Jackson 提供了一系列 on/off feature,它们在 Jackson 中由枚举定义,在 Spring Boot 中映射为环境属性:

枚举属性取值
tools.jackson.databind.cfg.DateTimeFeaturespring.jackson.datatype.datetime.<feature_name>truefalse
tools.jackson.databind.cfg.EnumFeaturespring.jackson.datatype.enum.<feature_name>truefalse
tools.jackson.databind.cfg.JsonNodeFeaturespring.jackson.datatype.json-node.<feature_name>truefalse
com.fasterxml.jackson.annotation.JsonInclude$Includespring.jackson.default-property-inclusionalwaysnon_nullnon_absentnon_defaultnon_empty
tools.jackson.databind.DeserializationFeaturespring.jackson.deserialization.<feature_name>truefalse
tools.jackson.core.json.JsonReadFeaturespring.jackson.json.read.<feature_name>truefalse
tools.jackson.core.json.JsonWriteFeaturespring.jackson.json.write.<feature_name>truefalse
tools.jackson.databind.MapperFeaturespring.jackson.mapper.<feature_name>truefalse
tools.jackson.databind.SerializationFeaturespring.jackson.serialization.<feature_name>truefalse

例如,要开启 pretty print,设置spring.jackson.serialization.indent_output=true。这里用到了宽松绑定(relaxed binding):属性中indent_output的大小写不必与对应枚举常量INDENT_OUTPUT完全一致。

这套环境配置应用到自动配置的JsonMapper.BuilderBean 上,因此对它和由该 builder 创建的任意 mapper(包括自动配置的JsonMapperBean)都生效。所有属性定义见 JacksonProperties.java,它通过@ConfigurationProperties("spring.jackson")绑定,还提供date-formatproperty-naming-strategytime-zonelocaledefault-lenienceconstructor-detector等字段。

通过定制器 Bean 做编程式微调

属性覆盖不了一切的场景(比如要按条件设置),Spring Boot 提供了两类定制器 Bean:

  • org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer:定制上下文中的JsonMapper.Builder。定制器可以排序——Boot 自带的定制器 order 为 0,因此你可以把自己的定制逻辑放在 Boot 的定制之前或之后。
  • org.springframework.boot.jackson.autoconfigure.JsonFactoryBuilderCustomizer:定制 builder 及其创建 mapper 所用的JsonFactory;也可以通过各种spring.jackson.factory属性配置工厂。

模块注册同样有两条自动通道:

  • 任意tools.jackson.databind.JacksonModule类型的 Bean 都会自动注册到自动配置的JsonMapper.Builder,并作用于它创建的所有JsonMapper实例。这是应用级贡献自定义模块的机制,为应用新增功能时推荐使用。
  • 通过 JavaServiceLoader机制参与发现的模块默认也会被找到并加入自动配置的JsonMapper.Builder。如果不需要这个行为,把spring.jackson.find-and-add-modules设为false

用 @JacksonComponent 注册自定义序列化器和反序列化器

如果你要自己写tools.jackson.databind.ValueSerializer/tools.jackson.databind.ValueDeserializer,常规做法是通过模块注册到 Jackson;Spring Boot 提供了替代方案:@org.springframework.boot.jackson.JacksonComponent注解,可以直接注册 Spring Bean。

它可以直接标注在ValueSerializerValueDeserializerKeyDeserializer实现上,也可以标注在把这些类作为内部类的类上。Spring Boot 文档中的示例如下(来自 MyJacksonComponent.java,使用时把MyObject换成你的对象类型):

import tools.jackson.core.JsonGenerator; import tools.jackson.core.JsonParser; import tools.jackson.databind.DeserializationContext; import tools.jackson.databind.JsonNode; import tools.jackson.databind.SerializationContext; import tools.jackson.databind.ValueDeserializer; import tools.jackson.databind.ValueSerializer; import org.springframework.boot.jackson.JacksonComponent; @JacksonComponent public class MyJacksonComponent { public static class Serializer extends ValueSerializer<MyObject> { @Override public void serialize(MyObject value, JsonGenerator jgen, SerializationContext context) { jgen.writeStartObject(); jgen.writeStringProperty("name", value.getName()); jgen.writeNumberProperty("age", value.getAge()); jgen.writeEndObject(); } } public static class Deserializer extends ValueDeserializer<MyObject> { @Override public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) { JsonNode tree = jsonParser.readValueAsTree(); String name = tree.get("name").stringValue(); int age = tree.get("age").intValue(); return new MyObject(name, age); } } }

所有ApplicationContext中的@JacksonComponentBean 都会自动注册到 Jackson。由于@JacksonComponent元标注了@Component,常规的组件扫描规则适用。

Spring Boot 还提供了org.springframework.boot.jackson.ObjectValueSerializerorg.springframework.boot.jackson.ObjectValueDeserializer基类,在序列化对象时是标准 Jackson 类的可用替代,细节见其 API 文档。

用 @JacksonMixin 给已有类混入注解

Jackson 支持 mixin,可以把额外注解混入目标类已声明的注解。Spring Boot 的 Jackson 自动配置会扫描应用包中用@org.springframework.boot.jackson.JacksonMixin标注的类,并把它们注册到自动配置的JsonMapper,注册由org.springframework.boot.jackson.JacksonMixinModule完成。适合无法修改源码、又想调整某类序列化行为的情况。

完全替换默认的 JsonMapper

如果需要彻底接管,有两种方式:定义JsonMapper类型的@Bean,或者(如果更喜欢 builder 方式)定义tools.jackson.databind.json.JsonMapper.Builder类型的@Bean

两点必须注意:

  • 定义JsonMapperBean 时,建议标注@Primary,因为它要替换的自动配置JsonMapper本身是@Primary的。
  • 无论哪种方式,这样做都会禁用JsonMapper的全部自动配置——前文的属性绑定、JacksonModule自动注册等都不会再作用于你定义的 Bean。

让定制生效于 HTTP 消息转换器

JsonMapper定制要影响 MVC/HTTP 客户端的 JSON 转换,还需要关注消息转换器这一层:

  • 如果你提供任何org.springframework.http.converter.json.JacksonJsonHttpMessageConverter类型的 Bean,它会替换 MVC 配置中的默认值。
  • 也可以声明org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizerBean 来添加转换器或覆盖某个默认转换器。

Spring Boot 文档中的示例展示了用自定义JsonMapper构建转换器并同时作用于服务端和客户端(完整代码见 MyHttpMessageConvertersConfiguration.java):

import java.text.SimpleDateFormat; import tools.jackson.databind.json.JsonMapper; import org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer; import org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer; import org.springframework.http.converter.HttpMessageConverters.ClientBuilder; import org.springframework.http.converter.HttpMessageConverters.ServerBuilder; import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; // 关键部分:构建自定义 JsonMapper 并贡献给 server 与 client JsonMapper jsonMapper = JsonMapper.builder() .defaultDateFormat(new SimpleDateFormat("yyyy-MM")) .build(); static class JacksonConverterCustomizer implements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer { private final JsonMapper jsonMapper; JacksonConverterCustomizer(JsonMapper jsonMapper) { this.jsonMapper = jsonMapper; } @Override public void customize(ClientBuilder builder) { builder.withJsonConverter(new JacksonJsonHttpMessageConverter(this.jsonMapper)); } @Override public void customize(ServerBuilder builder) { builder.withJsonConverter(new JacksonJsonHttpMessageConverter(this.jsonMapper)); } }

上面的JsonMapper是在定制器内部自行构建的,与自动配置的JsonMapper无关;这是与替换自动配置 Bean 不同的另一条控制路径,适合只希望替换 JSON 转换器所用 mapper 而不想关掉全部自动配置的场景。

从 Jackson 2 迁移:恢复旧的默认行为

对之前使用 Jackson 2 的应用,自动配置的JsonMapper可以设置为尽量接近 Spring Boot 当年为 Jackson 2 使用的默认值。把spring.jackson.use-jackson2-defaults设为true即可启用这些默认值,缓解迁移过程中的行为差异。

验证定制是否生效

验证路径就是请求一个 JSON 接口观察输出:Spring Boot 应用中的任何@RestController在 Jackson 3 位于 classpath 上时默认就渲染 JSON 响应,例如示例中的接口在http://localhost:8080/thing上直接返回对象的 JSON 表示。

  • 设置了spring.jackson.serialization.indent_output=true后,响应的 JSON 输出为格式化(pretty print)形式;
  • 注册了@JacksonComponent序列化器后,对应类型的 JSON 结构应与你serialize方法写入的字段一致,反序列化方向可提交 JSON 请求验证能否按你的deserialize逻辑还原;
  • 如果预期看到 JSON 却在浏览器里看到 XML,这是浏览器倾向发送偏好 XML 的Accept头导致的,换成Accept: application/json请求即可。

各路径的取舍:能用spring.jackson.*属性解决的不要写定制器;需要按条件编程式调整用JsonMapperBuilderCustomizer;行为与 Jackson 3 默认差异过大、短期不便调整时才用use-jackson2-defaults过渡;只有需要彻底接管时才定义JsonMapperJsonMapper.BuilderBean,并记住它会禁用全部自动配置。更多细节可参考 JSON 特性文档和 Spring MVC 常见问题文档中的 "Customize the Jackson JsonMapper" 一节。

【免费下载链接】spring-bootSpring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.项目地址: https://gitcode.com/gh_mirrors/sp/spring-boot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询