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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:02:49