Jackson 从 1.x 到 2.x 的演进,不仅是一次技术升级,更深刻影响了 Spring 生态(尤其是 Spring MVC 和 Spring Boot)的 JSON 处理方式。下面从 Jackson 自身差异 、Spring 对 Jackson 的集成变迁 、实际开发中的迁移注意事项 三个维度,系统梳理这一历程。
一、Jackson 1.x vs 2.x:核心差异回顾(精要版)
| 维度 | Jackson 1.x (org.codehaus.jackson) |
Jackson 2.x (com.fasterxml.jackson) |
|---|---|---|
| 包名 | org.codehaus.jackson.* |
com.fasterxml.jackson.* |
| 模块化 | 核心 + mapper 混合 | 拆分为 core / annotations / databind |
| 注解位置 | org.codehaus.jackson.map.annotate.* |
com.fasterxml.jackson.databind.annotation.* |
| 过滤 null | @JsonSerialize(include = Inclusion.NON_NULL) |
废弃 → 改用 @JsonInclude(Include.NON_NULL) |
| 异常体系 | JsonProcessingException 等 |
更细粒度(JsonParseException, DatabindException) |
| 扩展性 | 基础支持 | 更强(支持自定义 Module、AnnotationIntrospector 等) |
| 维护状态 | 已停止(~2013) | 活跃维护(当前 2.17+) |
✅ 关键结论 :两者二进制不兼容,不能共存于 classpath(会冲突)。
二、Spring 项目中 Jackson 的集成变迁
1. Spring Framework 3.x 时代(~2010--2013)
-
默认使用 Jackson 1.x。
-
需手动添加依赖:
xml<dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.13</version> </dependency> -
在 Spring MVC 中启用 JSON:
xml<mvc:annotation-driven /> <!-- 自动检测 classpath 下的 Jackson 1.x -->
⚠️ 此时若想用 Jackson 2.x,需显式配置
MappingJackson2HttpMessageConverter(名字带 "2" 就是为区分 1.x)。
2. Spring Framework 4.x 起(2013+):全面拥抱 Jackson 2.x
- 默认且仅支持 Jackson 2.x。
- 移除对 Jackson 1.x 的自动配置支持。
- 新增核心类:
MappingJackson2HttpMessageConverter(取代旧的MappingJacksonHttpMessageConverter)Jackson2ObjectMapperBuilder
- 自动配置条件:classpath 存在
com.fasterxml.jackson.databind.ObjectMapper
Spring Boot 的推动(2014+)
-
Spring Boot 1.0+ 默认内嵌 Jackson 2.x。
-
starter 依赖自动引入:
xml<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 传递依赖 jackson-databind 2.x --> </dependency> -
通过
application.properties轻松配置:propertiesspring.jackson.serialization.write-dates-as-timestamps=false spring.jackson.default-property-inclusion=NON_NULL
✅ 从此,新项目几乎不再接触 Jackson 1.x。
3. Spring Boot 2.x / 3.x:深度集成与现代化
-
Jackson 2.9+ ~ 2.15+ 成为事实标准。
-
支持 Java 8+ 特性(
Optional,LocalDateTime等开箱即用)。 -
通过
Jackson2ObjectMapperBuilderCustomizer定制:java@Bean public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { return builder -> builder.serializationInclusion(JsonInclude.Include.NON_EMPTY); } -
Spring Boot 3.x(基于 Jakarta EE 9+):
- 包名从
javax.*→jakarta.* - 但 Jackson 不受影响 (仍用
com.fasterxml.jackson)
- 包名从
三、实际开发中的关键差异与迁移要点
场景 1:自定义序列化器
Jackson 1.x(已过时):
java
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
public class MySerializer extends JsonSerializer<MyClass> {
@Override
public void serialize(MyClass value, JsonGenerator jgen, SerializerProvider provider) {
jgen.writeString("custom");
}
}
Jackson 2.x(现代写法):
java
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class MySerializer extends JsonSerializer<MyClass> {
@Override
public void serialize(MyClass value, JsonGenerator gen, SerializerProvider serializers) {
gen.writeString("custom");
}
}
🔁 只需改 import,逻辑几乎不变。
场景 2:注解使用变更
❌ Jackson 1.x 写法(在 2.x 中无效):
java
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
private String name;
✅ Jackson 2.x 正确写法:
java
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
private String name;
}
// 或字段级
@JsonInclude(Include.NON_EMPTY)
private List<String> tags;
📌 这是最常见的迁移错误!
场景 3:Spring 配置类变更
Spring 3.x + Jackson 1.x:
java
@Bean
public MappingJacksonHttpMessageConverter jacksonConverter() {
return new MappingJacksonHttpMessageConverter();
}
Spring 4.x+ + Jackson 2.x:
java
@Bean
public MappingJackson2HttpMessageConverter jackson2Converter() {
return new MappingJackson2HttpMessageConverter();
}
注意类名多了 "2"!
但在 Spring Boot 中,通常无需手动配置,自动装配即可。
场景 4:依赖冲突排查
若项目同时引入了 Jackson 1.x 和 2.x(例如老 jar 传递依赖),会出现:
ClassNotFoundExceptionNoSuchMethodErrorAbstractMethodError
解决方法:
bash
# Maven 查看依赖树
mvn dependency:tree | grep jackson
# 排除旧版本
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</exclusion>
四、总结:演进脉络与最佳实践
| 时间线 | 技术栈 | 建议 |
|---|---|---|
| 2010--2013 | Spring 3.x + Jackson 1.x | 仅维护旧系统 |
| 2013--2016 | Spring 4.x + Jackson 2.x 过渡期 | 主动迁移,替换包名和注解 |
| 2016 至今 | Spring Boot + Jackson 2.6+ | 使用 @JsonInclude,避免 include 属性 |
| 未来 | Spring Boot 3.x + Jackson 2.15+ | 拥抱 Java 17+,利用新特性(record、sealed class) |
✅ 最佳实践(现代 Spring Boot 项目):
- 不要手动管理 Jackson 依赖 ,由
spring-boot-starter-web控制版本。 - 用
@JsonInclude替代旧的include属性。 - 自定义序列化/反序列化时,继承
StdSerializer/StdDeserializer(比直接继承基类更安全)。 - 全局配置优先使用
application.yml,而非硬编码ObjectMapper。
如果你正在维护一个从 Spring 3.x 升级到 Spring Boot 的老系统,重点检查:
- 所有
import org.codehaus.jackson...→ 替换为com.fasterxml.jackson... - 所有
@JsonSerialize(include=...)→ 改为@JsonInclude(...) - 确保 classpath 没有残留 Jackson 1.x 的 jar
这样就能平滑过渡到现代 Jackson 2.x 生态。