Spring Boot POST接口接收对象列表时触发ClassCastException问题
问题根源
Spring Boot 默认使用 Jackson 处理请求体的反序列化,当你在 Controller 中接收 List<CompleteRequest> 类型的参数时,Jackson 只会实例化父类 CompleteRequest 的对象,即使请求体中包含子类的独有字段,也不会自动映射为子类实例,强行类型转换自然会抛出 ClassCastException。
解决方案:使用 Jackson 多态序列化注解
通过在父类上添加 Jackson 多态注解,明确告诉 Jackson 如何识别并反序列化为对应的子类实例。
1. 给父类添加多态注解
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" // 用于区分子类的标记字段,请求体必须携带该字段 ) @JsonSubTypes({ @JsonSubTypes.Type(value = TagRequest.class, name = "tag"), @JsonSubTypes.Type(value = DataRequest.class, name = "data") }) public class CompleteRequest { // 4个公共字段 private String commonField1; private String commonField2; private Integer commonField3; private Boolean commonField4; // 生成 getter、setter、构造方法 }
2. 定义子类
// TagRequest 子类 public class TagRequest extends CompleteRequest { // 独有字段 private String tagName; private Integer tagPriority; // 生成 getter、setter、构造方法 }
// DataRequest 子类 public class DataRequest extends CompleteRequest { // 独有字段 private String dataId; private Long dataSize; // 生成 getter、setter、构造方法 }
3. Controller 中处理请求
不需要强行转换,直接通过 instanceof 判断类型后处理:
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class RequestController { @PostMapping("/process-requests") public String processRequests(@RequestBody List<CompleteRequest> requestList) { for (CompleteRequest req : requestList) { if (req instanceof TagRequest) { TagRequest tagReq = (TagRequest) req; // 处理 TagRequest 逻辑 System.out.println("处理标签请求:" + tagReq.getTagName()); } else if (req instanceof DataRequest) { DataRequest dataReq = (DataRequest) req; // 处理 DataRequest 逻辑 System.out.println("处理数据请求:" + dataReq.getDataId()); } } return "请求处理完成"; } }
4. 正确的请求体格式
每个列表元素必须携带 type 字段,对应注解中定义的子类标记值:
[ { "type": "tag", "commonField1": "公共值1", "commonField2": "公共值2", "commonField3": 100, "commonField4": true, "tagName": "用户标签", "tagPriority": 1 }, { "type": "data", "commonField1": "公共值3", "commonField2": "公共值4", "commonField3": 200, "commonField4": false, "dataId": "DATA_001", "dataSize": 2048 } ]
可选方案:自定义反序列化器
如果不想在请求体中添加额外的 type 字段,可以自定义 Jackson 反序列化器,通过判断字段存在性来识别子类。但这种方式复杂度较高,不如注解方式简洁直观。
内容的提问来源于stack exchange,提问作者elvis
相关产品推荐
相关产品推荐

