
java record是java 16引入的一种特殊类,旨在作为不可变数据载体(immutable dtos)。它们自动生成构造函数、访问器、equals()、hashcode()和tostring()方法,极大地简化了数据类的定义。例如:
public record MyDTO(
String field1,
String field2
) { }对于Jackson库而言,从2.12.x版本开始,它已原生支持Java Record的序列化和反序列化。这意味着,只要JSON属性名与Record的组件名(即字段名)匹配,Jackson就能自动地将JSON对象映射到Record实例,而无需额外的注解。
然而,在某些情况下,即使使用了支持Record的Jackson版本(例如2.13.3),在尝试反序列化一个Record时,仍然可能会遇到以下异常:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.package.MyDTO` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
这个错误表明Jackson无法找到合适的构造器来创建MyDTO的实例。对于Record而言,Jackson应该能够识别其规范构造器,但在此场景下却失败了。
为了解决上述异常,一些开发者可能会采取一种临时但低效的策略:在Record的每个组件上显式地添加@JsonProperty注解,以指导Jackson如何映射JSON属性到构造器参数。
立即学习“Java免费学习笔记(深入)”;
import com.fasterxml.jackson.annotation.JsonProperty;
public record MyDTO(
@JsonProperty("field1")
String field1,
@JsonProperty("field2")
String field2
) { }这种方法确实能够解决反序列化问题,因为它明确地告诉了Jackson如何构建Record。然而,这种做法存在显著的缺点:
上述问题的根本原因通常不是Jackson本身不支持Record,而是在项目中存在Jackson版本冲突。即使您在项目的pom.xml(Maven)或build.gradle(Gradle)中明确指定了较新的Jackson版本(例如2.13.3),但由于项目中的其他依赖(如Spring Boot或其他第三方库)可能间接引入了旧版Jackson(例如2.11.x或更早版本),并且构建工具的依赖解析机制最终选择了旧版本。
旧版Jackson在设计时并未考虑Java Record,因此无法正确处理Record的规范构造器,导致在反序列化时抛出InvalidDefinitionException。
解决Jackson反序列化Record问题的关键在于确保整个项目中使用的是统一且支持Record的Jackson版本。
首先,需要确定项目中实际生效的Jackson版本。
Maven项目: 使用mvn dependency:tree命令。
mvn dependency:tree | grep jackson
仔细检查输出,查找所有与com.fasterxml.jackson相关的依赖,并注意它们的版本号。如果看到不同版本的Jackson库(如jackson-databind, jackson-core, jackson-annotations),则存在冲突。
Gradle项目: 使用gradle dependencies命令。
gradle dependencies --configuration runtimeClasspath | grep jackson
同样,分析输出以识别任何版本不一致的Jackson依赖。
一旦确认存在版本冲突,就需要显式地强制项目使用您期望的Jackson版本。
Maven项目: 在pom.xml的<properties>部分定义Jackson版本,并在<dependencyManagement>部分显式声明所有Jackson模块的版本。
<properties>
<jackson.version>2.13.3</jackson.version> <!-- 确保这里是支持Record的版本 -->
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- 添加其他Jackson模块,如jackson-datatype-jsr310 等,确保版本一致 -->
</dependencies>
</dependencyManagement>通过<dependencyManagement>,可以确保所有直接或间接依赖的Jackson模块都使用指定的版本。
Gradle项目: 在build.gradle中,可以在ext块中定义Jackson版本,并使用configurations.all或resolutionStrategy来强制统一版本。
ext {
jacksonVersion = '2.13.3' // 确保这里是支持Record的版本
}
configurations.all {
resolutionStrategy {
force "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}"
force "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}"
force "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}"
// 强制其他Jackson模块
}
}或者,如果使用Spring Boot的dependency-management-plugin,可以通过其提供的机制来管理:
plugins {
id 'org.springframework.boot' version '2.6.7' // 或更高版本
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:${jacksonVersion}" // 推荐使用Jackson BOM
}
}使用Jackson BOM(Bill of Materials)是管理Jackson版本的好方法,它能确保所有Jackson模块的版本兼容性。
完成版本统一后,重新构建并运行项目。此时,您的Record定义可以恢复到最简洁的形式,无需任何@JsonProperty注解:
public record MyDTO(
String field1,
String field2
) { }Jackson将能够正确地反序列化它。
Jackson对Java Record的原生支持极大地简化了不可变数据对象的处理。当遇到Jackson反序列化Record失败,并提示“no Creators”的异常时,首先应怀疑Jackson版本冲突。通过仔细检查项目的依赖树,并强制统一Jackson到支持Record的最新稳定版本(2.12.x或更高),可以消除冗余的@JsonProperty注解,实现更简洁、更易维护的代码,并充分利用Java Record和Jackson的强大功能。
以上就是Jackson反序列化Java Record的常见陷阱与版本兼容性解决方案的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号