You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot接口作为请求体实现多态时的反序列化错误问题

解决Spring多态请求体反序列化问题

问题场景

需要处理两种不同格式的POST请求:

{
   "notification": "order_creation_notification",
   "data": {
       "date": "22 Jan 2022"
   }
}
{
   "notification": "login_notification",
   "data": {
       "email": "johndoe@email.com",
       "at": "LA, USA"
   }
}

对应的Controller和实体类代码如下:

Controller代码

@PostMapping(value="/")
public void createNotification(@RequestBody NotificationRequest request) {
    // 业务逻辑
}  

请求体类

@JsonTypeInfo(use = Id.DEDUCTION)
@JsonSubTypes({
    @Type(OrderCreationNotification.class),
    @Type(LoginNotification.class)
})
public interface IData {
    
}
@AllArgsConstructor
@Getter
@Setter
public class OrderCreationNotification implements IData {
    private Date date;
}
@AllArgsConstructor
@Getter
@Setter
public class LoginNotification implements IData {
    private String email;
    private String at;
}
@AllArgsConstructor
@Getter
@Setter
public class NotificationRequest {
    private String notification;
    private IData data;
}

发送请求时出现反序列化错误:

JSON parse error: Cannot construct instance of `LoginNotification` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `LoginNotification` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 8, column: 13] (through reference chain: NotificationRequest[\"data\"])

解决方案

1. 修复构造器缺失问题

错误的直接原因是Jackson无法找到无参构造器来实例化实体类。虽然@AllArgsConstructor生成了全参构造,但Jackson默认需要无参构造完成对象实例化,后续再填充字段。

给所有IData的实现类添加无参构造器(使用Lombok的@NoArgsConstructor):

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class OrderCreationNotification implements IData {
    private Date date;
}
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class LoginNotification implements IData {
    private String email;
    private String at;
}

2. 优化多态反序列化配置(可选但推荐)

当前使用的Id.DEDUCTION是Jackson 2.12+的自动推导特性,依靠子类字段匹配来确定类型,存在字段重叠时的不确定性。更可靠的方式是利用外层的notification字段明确指定data的类型:

修改IData的注解配置:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
    property = "notification"
)
@JsonSubTypes({
    @Type(value = OrderCreationNotification.class, name = "order_creation_notification"),
    @Type(value = LoginNotification.class, name = "login_notification")
})
public interface IData {
    
}
  • EXTERNAL_PROPERTY:表示类型标识符来自外层对象的指定属性(即notification)
  • name:指定每个子类对应的notification字段值,确保类型匹配精准

验证

修改完成后重新发送请求,Jackson将正确识别data的类型并完成反序列化,不再抛出错误。

内容的提问来源于stack exchange,提问作者StudentWhoCurious

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:55:31