为何Jackson反序列化单字段DTO需无参构造,多字段则无需?
为什么单字段DTO需要@NoArgsConstructor才能被Jackson反序列化,多字段却不需要?
核心原因:Jackson对单参数构造器的特殊处理逻辑
Jackson在反序列化JSON对象时,构造器的选择逻辑会因类的字段数量不同产生差异:
1. 多字段DTO的情况(如你的StudentCreationDTO)
当类有多个字段,且存在一个参数数量与JSON字段数量完全匹配的构造器(这里是@AllArgsConstructor生成的构造器),Jackson会:
- 通过反射获取构造器的参数名称(Spring Boot默认开启参数名称保留,Lombok的
@AllArgsConstructor会配合编译器保留参数名) - 将JSON中的键与构造器参数名一一匹配,直接调用该构造器实例化对象,无需依赖无参构造器或setter方法。
你的StudentCreationDTO有4个字段,@AllArgsConstructor生成的构造器正好对应4个参数,Jackson能精准匹配每个参数对应的JSON字段,因此反序列化正常。
2. 单字段DTO的情况(如你的SubjectCreationDTO)
当类只有一个字段时,Jackson会优先尝试将JSON的原始值(比如纯字符串"Math")直接传入单参数构造器。但你发送的是JSON对象({"title":"Math"}),此时Jackson会陷入矛盾:
- 无法将整个JSON对象直接传给接收String类型的单参数构造器;
- 又找不到无参构造器来先实例化对象,再通过setter方法赋值。
最终就会抛出你遇到的错误:cannot deserialize from Object value (no delegate- or property-based Creator)。
两种可选解决方案
方案1:添加@NoArgsConstructor
给单字段DTO加上@NoArgsConstructor,让Jackson先创建空对象,再通过@Setter生成的方法设置字段值:
@AllArgsConstructor @NoArgsConstructor @Getter @Setter public class SubjectCreationDTO { private String title; }
方案2:给单参数构造器的参数添加@JsonProperty
显式告诉Jackson单参数构造器的参数对应JSON中的哪个字段,让Jackson能正确映射JSON对象的字段到构造器参数:
@AllArgsConstructor @Getter @Setter public class SubjectCreationDTO { @JsonProperty("title") private String title; }
(注:Lombok 1.18.16及以上版本,字段上的@JsonProperty会自动应用到@AllArgsConstructor生成的构造器参数上,无需手动编写构造器)
内容的提问来源于stack exchange,提问作者Alexandru Kullman
相关产品推荐
相关产品推荐

