SpringBoot + MyBatis-Plus 使用 listObjs 报 ClassCastException 的原因与解决办法

在项目中我们经常会遇到这种需求:

根据一组 ID 查询数据库,并返回指定字段列表。

我在写代码的时候,遇到了一个典型的坑,分享出来给大家。

一、问题背景

我的代码是这样写的(查询项目表的负责人信息):

@PostMapping("/getOwnerInfoList")

public Result getOwnerInfoList(@RequestBody List<Integer> pcIds) {

List<Map<String, Object>> result = pmPcService.listObjs(

new LambdaQueryWrapper<PmPc>()

.select(PmPc::getPcId, PmPc::getOwnerUserId, PmPc::getDocumentCode)

.in(PmPc::getPcId, pcIds),

pc -> {

PmPc p = (PmPc) pc; // 👈 报错点

Map<String, Object> map = new HashMap<>();

map.put("pcId", p.getPcId());

map.put("ownerUserId", p.getOwnerUserId());

map.put("documentCode", p.getDocumentCode());

return map;

}

);

return R.ok(result);

}

结果运行时直接报错:

java.lang.ClassCastException: java.lang.Integer cannot be cast to com.kakarote.pm.entity.PO.PmPc

二、原因分析

问题的关键在于 listObjs 方法的返回值

listObjs 的官方说明是:

查询并返回对象集合,默认只会返回查询结果的 第一列

也就是说,如果你 select 了三列(pcId, ownerUserId, documentCode),listObjs 默认只返回第一列 pcId

所以 pc 其实是 Integer,你强转成 PmPc 就会报 ClassCastException

如果你写了 resultHandler 回调,查询多列时返回的是 Object[],而不是实体对象。

三、正确的解决方案

方式一:直接用 list

最简单的方式就是不用 listObjs,而是用 list,这样返回的就是实体对象

复制代码
List<PmPc> list = pmPcService.list(
        new LambdaQueryWrapper<PmPc>()
                .select(PmPc::getPcId, PmPc::getOwnerUserId, PmPc::getDocumentCode)
                .in(PmPc::getPcId, pcIds)
);

List<Map<String, Object>> result = list.stream().map(p -> {
    Map<String, Object> map = new HashMap<>();
    map.put("pcId", p.getPcId());
    map.put("ownerUserId", p.getOwnerUserId());
    map.put("documentCode", p.getDocumentCode());
    return map;
}).collect(Collectors.toList());

return R.ok(result);

方式二:继续用 listObjs

如果一定要用 listObjs,正确写法如下:

复制代码
List<Map<String, Object>> result = pmPcService.listObjs(
        new LambdaQueryWrapper<PmPc>()
                .select(PmPc::getPcId, PmPc::getOwnerUserId, PmPc::getDocumentCode)
                .in(PmPc::getPcId, pcIds),
        obj -> {
            Object[] arr = (Object[]) obj;  // listObjs 查询多列时返回 Object[]
            Map<String, Object> map = new HashMap<>();
            map.put("pcId", arr[0]);
            map.put("ownerUserId", arr[1]);
            map.put("documentCode", arr[2]);
            return map;
        }
);

四、总结

  • listObjs 默认只返回第一列,别以为它能直接返回实体

  • 如果你需要实体对象,用 list 更直观。

  • 如果你需要自定义对象,用 listObjs + Object[] 来处理。

💡 推荐:

如果业务中经常要查多列 → 用 list

如果只查单列(比如只查 id 列表) → 用 listObjs