Jackson 3 迁移核心注意点总结

一、核心要点(必掌握,迁移基础)

1. 环境基线升级: 最低支持 JDK 17(2.x 为 JDK 8),项目需先完成 JDK 升级适配。

2. 包名与依赖变更:

  • Maven groupId:com.fasterxml.jackson → tools.jackson(jackson-annotations 除外,仍用 2.x 版本)Java 导入包:
  • com.fasterxml.jackson.xxxtools.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 方法和兼容工具减少手动改造成本。

相关推荐
梦未8 小时前
Spring控制反转与依赖注入
java·后端·spring
喜欢流萤吖~8 小时前
Lambda 表达式
java
ZouZou老师9 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
曼巴UE59 小时前
UE5 C++ 动态多播
java·开发语言
VX:Fegn08959 小时前
计算机毕业设计|基于springboot + vue音乐管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
程序员鱼皮9 小时前
刚刚,IDEA 免费版发布!终于不用破解了
java·程序员·jetbrains
Hui Baby10 小时前
Nacos容灾俩种方案对比
java
曲莫终10 小时前
Java单元测试框架Junit5用法一览
java
成富10 小时前
Chat Agent UI,类似 ChatGPT 的聊天界面,Spring AI 应用的测试工具
java·人工智能·spring·ui·chatgpt