一、核心要点(必掌握,迁移基础)
1. 环境基线升级: 最低支持 JDK 17(2.x 为 JDK 8),项目需先完成 JDK 升级适配。
2. 包名与依赖变更:
- Maven groupId:com.fasterxml.jackson → tools.jackson(jackson-annotations 除外,仍用 2.x 版本)Java 导入包:
- com.fasterxml.jackson.xxx → tools.jackson.xxx(com.fasterxml.jackson.annotation 保留不变)
3. 核心 API 不可变性: ObjectMapper(及子类)、JsonFactory(及子类)变为完全不可变,必须通过 Builder 模式构建(不再支持直接 set 配置)。
java
JsonMapper m=JsonMapper.builder().build();
JsonFactory f = JsonFactory.builder().build();
4 .异常体系重构: 所有异常改为非检查型(继承 RuntimeException),核心异常类重命名(如 JsonProcessingException → JacksonException)。 5. 格式绑定强制化: 必须使用格式对齐的 ObjectMapper 子类(如 JsonMapper、YAMLMapper、XmlMapper),禁止 new ObjectMapper(new YAMLFactory()) 写法。 6. Java 8 模块内置: jackson-module-parameter-names、jackson-datatype-jdk8、jackson-datatype-jsr310 已整合到 jackson-databind,无需单独依赖。
二、关键变更(影响代码改造)
1. 内容移除
- 版本标记为 @Deprecated 的方法、字段、类全部删除( 参考 2.20 javadoc 替换为替代方案)。
- 移除模块 jackson-module-jsonSchema 、jackson-datatype-hibernateX。
- 移除功能:格式自动检测(DataFormatDetector 等相关类)、ObjectMapper.canSerialize()/canDeserialize() 方法。
- JsonParser
canWriteBinaryNatively(), canWriteFormattedNumbers()分别替为StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY / StreamWriteCapability.CAN_WRITE_FORMATTED_NUMBERS - JsonFactory
getCodec() 、 setCodec()被移除 - com.fasterxml.jackson.databind.MappingJsonFactory 被移除
- com.fasterxml.jackson.core.ObjectCodec 被移除,替换为 2 个独立的接口: tools.jackson.core.ObjectReadContext(实现类:DeserializationContext) , tools.jackson.core.ObjectWriteContext(实现类: SerializationContext )
- tools.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator 已不再公开。请使用 BasicPolymorphicTypeValidator.builder()
- JsonGenerator.setPrettyPrinter() 被移除
- request payload 能力被移除
- BufferRecyclers.SYSTEM_PROPERTY_TRACK_REUSABLE_BUFFERS 被移除
- TokenStreamFactory.Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING 被移除
- 在 Jackson 2.x 的 JsonFactory 类中,接受 URL 参数的工厂方法将被移除
2. 类与方法重命名(高频变更)
| 2.x 旧名称 | 3.x 新名称 |
|-----------------------------------------------------|---------------------------------------------------------|---|---------------------------------|------------------------------------|
| JsonProcessingException | JacksonException(基类) |
| JsonParseException | StreamReadException |
| JsonEOFException | UnexpectedEndOfInputException | | JsonGenerationException | StreamWriteException |
| JsonGenerator.writeObject() | JsonGenerator.writePOJO() |
| JsonGenerator.getCurrentValue() | JsonGenerator.currentValue() | | JsonGenerator.setCurrentValue() | JsonGenerator.assignCurrentValue() |
| JsonGenerator.getCodec() | JsonGenerator.objectWriteContext() |
| JsonParser.getCurrentLocation() | JsonParser.currentLocation() |
| JsonParser.getTokenLocation() | JsonGenerator.currentTokenLocation() |
| JsonParser.getCurrentValue() | JsonParser.currentValue() |
| JsonParser.setCurrentValue() | JsonParser.assignCurrentValue() |
| JsonParser."xxxTextYyy"() 格式 如(getTextCharacters()) | JsonParser."xxxStringYyy"() 格式 如(getStringCharacters()) |
| JsonParser.getCodec() | JsonParser.objectReadContext() |
| JsonToken.FIELD_NAME | JsonToken.PROPERTY_NAME |
| JsonFactory | TokenStreamFactory |
| JsonStreamContext | TokenStreamContext |
| JsonLocation | TokenStreamLocation |
| JsonDeserializer | ValueDeserializer |
| JsonSerializer | ValueSerializer |
| JsonMappingException | DatabindException |
| Module | JacksonModule(避免与 JDK Module 冲突) |
| TextNode | StringNode |
| BeanSerializerModifier | ValueSerializerModifier |
| BeanDeserializerModifier | ValueDeserializerModifier |
| SerializerProvider | SerializationContext |
| TextNode | StringNode |
| AnnotationIntrospector.findDefaultCreator() | findPreferredCreator() |
| JsonNode.elements() | JsonNode.values() |
| ContainerSerializer | StdContainerSerializer |
| ObjectMapper.getRegisteredModuleIds() | ObjectMapper.registeredModules() |
| TreeNode.propertyNames() 的返回类型 | 从 Iterator 更改为 Collection |
| TreeNode.isContainerNode() | TreeNode. isContainer() |
| JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT | JsonGenerator.Feature.AUTO_CLOSE_CONTENT |
3. 配置默认值变更(易引发行为差异)
| 枚举 | 配置项 | 2.x 默认值 | 3.x 默认值 | 影响说明 |
|---|---|---|---|---|
| DeserializationFeature | FAIL_ON_TRAILING_TOKENS | 关闭 | 开启 | 校验 JSON 末尾是否存在多余字符(如解析对象后还有额外的逗号 / 字符),提升数据合法性校验,但会增加少量解析开销;若输入数据可信(如内部系统交互),可关闭以恢复 2.x 性能。 |
| FAIL_ON_UNKNOWN_PROPERTIES | 开启 | 关闭 | 反序列化时遇到目标类不存在的字段,不再抛出 UnrecognizedPropertyException,而是直接忽略;可能掩盖字段名拼写错误、接口字段变更等问题,建议在测试环境开启该配置,生产环境按需关闭。 | |
| READ_ENUMS_USING_TO_STRING | 关闭 | 开启(迁移至 EnumFeature) | 反序列化枚举时,默认按 Enum.toString() 结果匹配(2.x 默认按枚举名称 / 索引);若枚举重写了 toString(),会改变反序列化逻辑,需确认枚举值映射规则,或显式配置 EnumFeature.READ_ENUMS_USING_TO_STRING=false 回退。 | |
| FAIL_ON_NULL_FOR_PRIMITIVES | 关闭 | 开启 | 反序列化时,若基本类型(int/long/boolean 等)字段接收到 null 值,会抛出 DatabindException;2.x 会默认赋值基本类型默认值(如 int=0),可能暴露空值处理漏洞,但也会导致原有依赖 "空值转默认值" 的代码报错。 | |
| SerializationFeature | WRITE_ENUMS_USING_TO_STRING | 关闭 | 开启(迁移至 EnumFeature) | 序列化枚举时,默认输出 Enum.toString() 结果(2.x 默认输出枚举名称);若枚举重写了 toString(),序列化结果会变化,需统一枚举序列化规则,或配置 EnumFeature.WRITE_ENUMS_USING_TO_STRING=false。 |
| FAIL_ON_EMPTY_BEANS | 开启 | 关闭 | 序列化无属性 / 无 getter 的空 Bean 时,不再抛出 JsonMappingException,而是输出空对象 {};避免因 Bean 结构临时调整导致序列化失败,但需注意空对象可能不符合下游系统的解析预期。 | |
| FAIL_ON_ORDER_MAP_BY_INCOMPARABLE_KEY | 开启 | 关闭 | 序列化 SortedMap 时,若 Key 不实现 Comparable 接口,不再抛出异常;2.x 会强制校验 Key 的可比较性,3.x 放宽限制,但可能导致 Map 排序混乱,需确保 SortedMap 的 Key 符合 Comparable 规范。 | |
| WRITE_DURATIONS_AS_TIMESTAMPS | 开启 | 关闭(迁移至 DateTimeFeature) | 序列化 java.time.Duration 时,默认输出 ISO-8601 字符串(如 PT1H30M),而非 2.x 的毫秒数时间戳;需确认下游系统是否兼容 Duration 的字符串格式,或配置 DateTimeFeature.WRITE_DURATIONS_AS_TIMESTAMPS=true 回退。 | |
| WRITE_DATES_AS_TIMESTAMPS | 开启 | 关闭(迁移至 DateTimeFeature) | 序列化日期时间类型(如 LocalDateTime/Date)时,默认输出 ISO-8601 字符串(如 2025-12-09T10:00:00),而非 2.x 的毫秒时间戳;会改变接口返回的日期格式,需同步更新前端 / 下游系统的解析逻辑。 | |
| WRITE_DATE_KEYS_AS_TIMESTAMPS | 关闭 | 关闭(迁移至 DateTimeFeature) | 无默认值变化,但配置项归属从 SerializationFeature 迁移至 DateTimeFeature;代码中需替换配置引用路径,否则会报 "配置项不存在" 错误。 | |
| StreamReadFeature | USE_FAST_DOUBLE_PARSER | 关闭 | 开启 | 解析浮点数字段时使用更快的双精度解析器(基于 jdk.incubator.vector 或优化算法);提升浮点数解析性能,但极端场景下可能存在精度差异(概率极低),需校验高精度浮点数据的解析结果。 |
| USE_FAST_BIG_NUMBER_PARSER | 关闭 | 开启 | 解析大数字(如 BigDecimal/BigInteger)时使用优化解析器;提升大数字解析效率,无兼容性风险,但需确保解析后的大数精度符合业务要求。 | |
| StreamWriteFeature | USE_FAST_DOUBLE_WRITER | 关闭 | 开启 | 序列化浮点数时使用更快的双精度写入器;提升浮点数字段序列化性能,极端场景可能存在小数位输出格式差异(如 0.1 变为 0.100000001),需校验金融 / 高精度场景的浮点输出。 |
| TokenStreamFactory.Feature | INTERN_PROPERTY_NAMES | 启用 | 关闭 | 不再对 JSON 属性名进行字符串驻留(String Intern);减少内存占用(避免常量池膨胀),但频繁解析相同属性名的 JSON 时,会增加字符串创建开销,高并发场景可按需重新开启。 |
| MapperFeature | USE_STD_BEAN_NAMING | 关闭 | 移除(始终启用) | 强制使用标准 JavaBean 命名规范(如 getXxx() 对应字段 xxx);2.x 需手动开启,3.x 内置生效,若代码依赖非标准命名(如 getXXX() 对应 XXX),会导致字段序列化 / 反序列化失败。 |
| AUTO_DETECT_xxx(CREATORS/FIELDS/GETTERS/IS_GETTERS/SETTERS) | 开启 | 移除 | 不再自动检测 Bean 的创建器 / 字段 / 访问器,需显式配置可见性规则;2.x 依赖自动检测的场景(如无注解的私有字段序列化)会失效,需通过 changeDefaultVisibility 配置字段 / 方法的可见性。 | |
| ALLOW_FINAL_FIELDS_AS_MUTATORS | 启用 | 关闭 | 禁止通过反射修改 final 字段的值;2.x 允许强制修改 final 字段(非规范行为),3.x 禁用后,依赖 "final 字段反序列化赋值" 的代码会报错,需改为通过构造器 / 工厂方法初始化 final 字段。 | |
| DEFAULT_VIEW_INCLUSION | 启用 | 关闭 | 未指定 @JsonView 时,不再默认序列化所有字段,仅序列化无 View 注解的字段;若代码依赖 "默认包含所有字段" 的逻辑,需显式配置 MapperFeature.DEFAULT_VIEW_INCLUSION=true,或补全 @JsonView 注解。 | |
| USE_GETTERS_AS_SETTERS | 启用 | 关闭 | 不再将 getXxx() 方法当作 setXxx() 使用(如反序列化集合字段时调用 getter 获取集合后添加元素);2.x 为兼容 JAXB 的非规范行为,3.x 禁用后,需为集合 / 映射字段添加显式的 setter 方法。 | |
| SORT_PROPERTIES_ALPHABETICALLY | 关闭 | 开启 | 序列化 POJO 时默认按字段名字母排序输出;2.x 按字段定义顺序输出,3.x 改变输出顺序,可能导致依赖字段顺序的签名校验(如 MD5 验签)失败,需显式配置 @JsonPropertyOrder 固定顺序。 | |
| OVERRIDE_PUBLIC_ACCESS_MODIFIERS | 启用 | 关闭 | 不再覆盖公共字段 / 方法的访问修饰符(如强制访问 public final 方法);2.x 可通过反射突破访问限制,3.x 禁用后,需确保 Bean 的字段 / 方法访问权限符合序列化要求(如 public getter)。 | |
| DateTimeFeature | ONE_BASED_MONTHS | 关闭 | 开启 | 解析 / 序列化日期时,月份按 "1 基" 处理(1=1 月,12=12 月);2.x 部分场景为 "0 基"(0=1 月),修复了月份解析的反直觉问题,但需校验老数据中 "0 基月份" 的兼容性(如 2025-00-09 会解析失败)。 |
| StreamReadConstraints | DEFAULT_MAX_DEPTH | 1000 | 500 | JSON 嵌套解析的最大深度从 1000 降至 500;限制深层嵌套 JSON 的解析,防止栈溢出攻击,但解析超过 500 层的嵌套 JSON 时会抛出 StreamConstraintsException,需调整超大嵌套 JSON 的解析限制。 |
| StreamWriteConstraints | DEFAULT_MAX_DEPTH | 1000 | 500 | JSON 嵌套序列化的最大深度从 1000 降至 500;序列化深层嵌套对象(如递归引用的对象)时会提前终止,需优化对象结构,或通过 StreamWriteConstraints.builder().maxDepth(1000) 调整限制。 |
4. 功能拆分与迁移
- 流式 API 特性拆分: JsonParser.Feature → StreamReadFeature(通用)+ JsonReadFeature(JSON 专用); JsonGenerator.Feature → StreamWriteFeature + JsonWriteFeature(其他格式如 XML/YAML 同理)。
- 迁移配置:
| 属性/方法 | 原位置 | 迁移位置 |
|---|---|---|
| ADJUST_DATES_TO_CONTEXT_TIME_ZONE | DeserializationFeature | DateTimeFeature |
| READ_DATE_TIMESTAMPS_AS_NANOSECONDS | DeserializationFeature | DateTimeFeature |
| FAIL_ON_NUMBERS_FOR_ENUMS | DeserializationFeature | EnumFeature |
| READ_ENUMS_USING_TO_STRING | DeserializationFeature | EnumFeature |
| READ_UNKNOWN_ENUM_VALUES_AS_NULL | DeserializationFeature | EnumFeature |
| READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE | DeserializationFeature | EnumFeature |
| WRITE_DATES_AS_TIMESTAMPS | SerializationFeature | DateTimeFeature |
| WRITE_DATE_KEYS_AS_TIMESTAMPS | SerializationFeature | DateTimeFeature |
| WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS | SerializationFeature | DateTimeFeature |
| WRITE_DATES_WITH_CONTEXT_TIME_ZONE | SerializationFeature | DateTimeFeature |
| WRITE_DURATIONS_AS_TIMESTAMPS | SerializationFeature | DateTimeFeature |
| WRITE_DATES_WITH_ZONE_ID | SerializationFeature | DateTimeFeature |
| WRITE_ENUMS_USING_TO_STRING | SerializationFeature | EnumFeature |
| WRITE_ENUMS_USING_INDEX | SerializationFeature | EnumFeature |
| WRITE_ENUM_KEYS_USING_INDEX | SerializationFeature | EnumFeature |
| createContextual() | ContextualDeserializer | ValueDeserializer |
| createContextual() | ContextualSerializer | ValueSerializer |
| resolve() | ResolvableDeserializer | ValueDeserializer |
| resolve() | ResolvableSerializer | ValueSerializer |
三、注意事项(避坑关键)
1. 依赖管理建议
优先使用 jackson-bom 统一版本(避免 jackson-annotations 版本冲突):
xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>tools.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>3.0.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
无需手动引入 jackson-core 和 jackson-annotations,jackson-databind 会自动传递依赖。
2. 代码改造注意
ObjectMapper 构建: 必须用 Builder 模式,示例:
java
// 3.x 正确写法
JsonMapper mapper = JsonMapper.builder()
.enable(JsonWriteFeature.ESCAPE_NON_ASCII)
.changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL))
.build();
// 重新配置已有 mapper(不可变对象无法直接修改)
JsonMapper newMapper = mapper.rebuild()
.enable(SerializationFeature.INDENT_OUTPUT)
.build();
泛型类型校验: LaissezFaireSubTypeValidator 不再公开,需用 BasicPolymorphicTypeValidator 构建:
java
BasicPolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
.allowIfSubType("com.example")
.build();
日期格式/时区配置: UTC 的默认形式现在尾部是 Z ,而不是像 2.x 版本中的 +00 。
java
//错误的方式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"));
mapper.setTimeZone(TimeZone.getDefault());
//正确的方式
ObjectMapper mapper = JsonMapper.builder()
.defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"))
.defaultTimeZone(TimeZone.getDefault())
.build();
序列化配置:
java
//错误的方式
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//正确的方式
ObjectMapper mapper = JsonMapper.builder()
.changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL))
.changeDefaultPropertyInclusion(incl -> incl.withContentInclusion(JsonInclude.Include.NON_NULL))
.build();
可见性配置: MapperFeature.AUTO_DETECT_XXX 已移除,需通过 changeDefaultVisibility 配置:
java
//错误的方式
mapper.disable(MapperFeature.AUTO_DETECT_FIELDS);
//正确的方式
ObjectMapper mapper = JsonMapper.builder()
.changeDefaultVisibility(vc ->
vc.withFieldVisibility(JsonAutoDetect.Visibility.NONE))
.build();
包含类型信息配置:
java
//错误的方式
mapper.activateDefaultTypingAsProperty(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS,
"@class");
//正确的方式
var typeValidator = BasicPolymorphicTypeValidator.builder()
.allowIfSubType("my.package.base.name.")
.allowIfSubType("java.util.concurrent.")
.allowIfSubTypeIsArray()
// ...
.build();
ObjectMapper mapper = JsonMapper.builder()
.activateDefaultTypingAsProperty(typeValidator, DefaultTyping.NON_CONCRETE_AND_ARRAYS, "@class")
.build();
JsonNode 处理中的 DecimalNode 创建策略 通过 JsonNodeFactory 创建 DecimalNode 时,旧行为:可能会自动截断尾随零(如 1.200 → 1.2)新行为:默认不截断尾随零,保持最小限度修剪
java
// 示例:不同的表示方式
BigDecimal value1 = new BigDecimal("1.200"); // 三位小数
BigDecimal value2 = new BigDecimal("1.2"); // 一位小数
// 新行为:DecimalNode会保持原始精度
// value1 仍会表示为 "1.200"
// value2 仍会表示为 "1.2"
Month 序列化/反序列化行为变更
java
// java.time.Month 枚举
public enum Month {
JANUARY, // 1
FEBRUARY, // 2
// ...
DECEMBER // 12
}
// Jackson 2.x 序列化结果(默认)
{"month": "JANUARY"} // 或使用索引:{"month": 0}
// Jackson 3.x 序列化结果(默认)
{"month": 1} // 直接使用 Month 的数值(1-12)
3. 性能优化点
关闭末尾字符校验: 若输入数据可信,可禁用 FAIL_ON_TRAILING_TOKENS 减少开销:
java
JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS).build();
缓冲区回收配置: 3.x 默认使用双端队列回收池,高并发场景可切换回 2.x 的 ThreadLocal 池:
java
JsonFactory factory = JsonFactory.builder() .recyclerPool(JsonRecyclerPools.threadLocalPool()) .build();
JsonMapper mapper = JsonMapper.builder(factory).build();
4. 兼容性适配
- 若需保留 2.x 部分默认行为,可使用 JsonMapper.builderWithJackson2Defaults() 快速迁移(但无法覆盖所有配置)。
- 单元测试需重点检查:字段序列化顺序、日期格式、未知字段处理、枚举序列化方式等受默认配置变更影响的场景。
5. 生态支持
- Spring 已在 2025.10 版本支持 Jackson 3.x(需升级 Spring 相关依赖)。
- 可使用 OpenRewrite 工具自动完成部分迁移(参考:docs.openrewrite.org/recipes/jav...
总结
Jackson 3.x 迁移的核心是 "环境升级 + 依赖变更 + Builder 模式适配 + 废弃 API 替换",关键在于处理包名、不可变对象构建和默认配置变更带来的兼容性问题。建议先升级 JDK 17,再通过依赖替换、代码批量改造(重点是 ObjectMapper 构建和异常处理)、单元测试验证逐步完成迁移,优先使用官方提供的 Builder 方法和兼容工具减少手动改造成本。