0

0

Jackson反序列化深度解析:何时需要@JsonCreator及其替代方案

霞舞

霞舞

发布时间:2025-07-14 14:54:02

|

1149人浏览过

|

来源于php中文网

原创

jackson反序列化深度解析:何时需要@jsoncreator及其替代方案

本文深入探讨了Jackson库在处理带有final字段的Java对象时,反序列化可能遇到的MismatchedInputException问题。我们将详细解释Jackson默认的反序列化机制,并介绍两种核心解决方案:显式使用@JsonCreator注解指定构造器,以及利用ParameterNamesModule实现参数的自动化映射。同时,文章还将剖析这两种方法在单参数和多参数构造器场景下的具体行为差异与注意事项。

1. 理解Jackson的反序列化机制与final字段的挑战

Jackson是一个功能强大的JSON处理库,在将JSON字符串反序列化为Java对象时,其默认机制通常遵循以下步骤:

  1. 查找无参构造器: Jackson会尝试调用目标类的无参构造器来实例化对象。
  2. 通过Setter方法赋值: 实例化后,Jackson会根据JSON字段名查找对应的Setter方法(例如,JSON中的"alias"对应setAlias()方法),然后通过这些Setter方法将值赋给对象的属性。

然而,当类中包含final修饰的字段时,这种默认机制就会遇到障碍。final字段一旦被初始化,就不能再次赋值。这意味着:

  • 如果一个类只有final字段且没有无参构造器(例如,Lombok的@Data注解在有final字段时会自动生成一个包含所有final字段的构造器,而不会生成无参构造器),Jackson将无法通过无参构造器创建实例。
  • 即使能够创建实例,final字段也无法通过Setter方法进行赋值,因为它们在对象创建后就不能被重新分配。

当Jackson尝试对如下User类进行反序列化时,就会抛出MismatchedInputException:

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;

@Data
public final class User implements Serializable {
    @JsonProperty("alias")
    private final String alias; // final 字段
}

错误信息通常会指示“Cannot construct instance... (no delegate- or property-based Creator)”,明确指出Jackson无法找到合适的创建者(构造器或工厂方法)来实例化对象并填充final字段。这是因为final字段必须在对象构造时一次性初始化。

2. 解决方案一:使用@JsonCreator显式指定构造器

解决final字段反序列化问题的最直接方法是显式地告诉Jackson应该使用哪个构造器来创建对象,并如何将JSON字段映射到构造器的参数上。这可以通过@JsonCreator注解和@JsonProperty注解的组合实现。

  • @JsonCreator: 标注在构造器或静态工厂方法上,指示Jackson在反序列化时使用此方法来创建对象实例。
  • @JsonProperty: 标注在构造器参数上,明确指定JSON字段名与该参数的映射关系。

以下是修改后的User类示例:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;

@Data
public final class User implements Serializable {
    @JsonProperty("alias")
    private final String alias;

    @JsonCreator // 显式指定此构造器为JSON创建者
    public User(@JsonProperty("alias") String alias) { // 使用@JsonProperty映射参数
        this.alias = alias;
    }
}

通过这种方式,Jackson在反序列化JSON(例如{"alias": "Smith"})时,会查找带有@JsonCreator的构造器,并根据@JsonProperty("alias")将JSON中的"alias"值传递给构造器的alias参数,从而成功创建并初始化User对象。

3. 解决方案二:借助ParameterNamesModule自动化参数映射

当项目中存在大量带有final字段的类,并且希望避免为每个构造器手动添加@JsonCreator和@JsonProperty时,可以考虑使用Jackson的ParameterNamesModule。这个模块能够利用Java 8及更高版本编译时生成的参数名信息(需要使用-parameters编译选项),自动将JSON字段映射到构造器参数。

3.1 引入依赖

首先,需要在项目的pom.xml中添加jackson-modules-java8的依赖:


    com.fasterxml.jackson.module
    jackson-modules-java8
    2.13.3 

3.2 配置ObjectMapper

接下来,需要将ParameterNamesModule注册到ObjectMapper中。在Spring Boot应用中,可以通过定义一个@Bean来完成:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.module.ParameterNamesModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {

    @Bean
    public ParameterNamesModule parameterNamesModule() {
        // 配置模块以使用属性模式进行参数绑定
        return new ParameterNamesModule(JsonCreator.Mode.PROPERTIES);
    }
}

3.3 编译选项要求

为了让ParameterNamesModule正常工作,Java编译器在编译源代码时必须包含参数名信息。这通常通过在maven-compiler-plugin中添加-parameters选项来实现:

慧中标AI标书
慧中标AI标书

慧中标AI标书是一款AI智能辅助写标书工具。

下载

    
        
            org.apache.maven.plugins
            maven-compiler-plugin
            3.8.1
            
                true 
            
        
    

在正确配置后,对于User类,如果其构造器只有一个参数,即使启用了ParameterNamesModule,仍然需要为该参数添加@JsonProperty。

4. 重要注意事项与特殊情况

尽管ParameterNamesModule提供了便利,但在特定情况下仍需注意其行为:

4.1 单参数构造器的特殊处理

ParameterNamesModule在处理单参数构造器时有一个重要的“陷阱”。根据Jackson的文档,对于单参数构造器,即使启用了ParameterNamesModule并设置为JsonCreator.Mode.PROPERTIES模式,仍然需要显式地在构造器参数上使用@JsonProperty注解。这是为了保持与旧版本Jackson行为的兼容性。

这意味着,对于像User类这样只有一个final字段并由Lombok生成单参数构造器的场景,即使你配置了ParameterNamesModule,也仍然需要像解决方案一那样,手动为构造器添加@JsonCreator和为参数添加@JsonProperty。

// 即使启用了ParameterNamesModule,对于单参数构造器,仍需要:
@Data
public final class User implements Serializable {
    @JsonProperty("alias")
    private final String alias;

    @JsonCreator // 仍然需要
    public User(@JsonProperty("alias") String alias) { // 仍然需要
        this.alias = alias;
    }
}

4.2 多参数构造器的自动映射

与单参数构造器不同,ParameterNamesModule在处理多参数构造器时表现得更为“智能”。对于拥有两个或更多参数的构造器,如果启用了ParameterNamesModule,Jackson通常可以自动识别参数名并将其与JSON字段进行映射,而无需显式地在每个参数上添加@JsonProperty。

这就是为什么在原始问题中,Multiplication类(包含factorA和factorB两个final字段)在某些情况下可能不需要@JsonCreator或@JsonProperty就能成功反序列化:

@Data
public final class Multiplication implements Serializable {
    @JsonProperty("factorA")
    private final Integer factorA;
    @JsonProperty("factorB")
    private final Integer factorB;
    // Lombok会生成一个Multiplication(Integer factorA, Integer factorB)构造器
}

如果ParameterNamesModule已配置,或者Jackson在没有@JsonCreator的情况下能够推断出多参数构造器(尤其当它是唯一的公共构造器时),它就可以直接使用该构造器并基于参数名进行映射。Jackson的内部逻辑在处理多参数构造器时,其默认行为更倾向于使用参数名进行绑定。

5. 总结

在Jackson反序列化处理带有final字段的Java对象时,核心挑战在于final字段的不可变性与Jackson默认的无参构造器+Setter机制之间的冲突。

  • 首选且最明确的解决方案: 使用@JsonCreator显式标记构造器,并为构造器参数标注@JsonProperty。这提供了最强的控制力,并且在所有情况下都有效。
  • 自动化但有局限的解决方案: 引入ParameterNamesModule可以简化多参数构造器的反序列化配置,减少冗余的@JsonProperty注解。然而,请务必记住其对单参数构造器的特殊要求——即使启用了该模块,单参数构造器仍需在参数上使用@JsonProperty。

理解这些机制和它们的细微差别,能帮助开发者更有效地处理Jackson反序列化中的final字段问题,并根据项目需求选择最合适的策略,兼顾代码的简洁性和可维护性。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

841

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

742

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

739

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

399

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
RunnerGo从入门到精通
RunnerGo从入门到精通

共22课时 | 1.7万人学习

尚学堂Mahout视频教程
尚学堂Mahout视频教程

共18课时 | 3.2万人学习

Linux优化视频教程
Linux优化视频教程

共14课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号