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

Spring Data Mongo存储含Pageable数据后查询报NoSuchMethodException问题

问题描述

我遇到了一个非常奇怪的Bug,具体场景如下:
我向数据库中存储inputData字段数据,实现代码如下:

Map<String, Object> params = new HashMap<>();
params.put("all", all);
params.put("pageable", pageable);

myObj.setInputData(params);

...
then repo.save(myObj);

数据库实际存储效果可参考对应字段截图。
但当我调用findByTestId方法查询数据时,抛出如下异常:

java.lang.NoSuchMethodException: org.springframework.data.domain.Sort$Order.() at
java.base/java.lang.Class.getConstructor0(Class.java:3349) at
java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553) at
org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:146)

我的Repository层定义代码如下:

public interface DataRepository extends MongoRepository<Data, String> {
   Optional<Data> findByTestId(String testid);
}

只要移除inputData中存储的pageable对象,查询功能即可恢复正常。我不清楚HashMap中存储的pageable字段为何会干扰查询逻辑,也不知道该如何修复该问题。
我的核心诉求是查询时可以正常取回已存储的inputData数据,供后续业务逻辑使用。

补充说明:我已尝试使用自定义对象替代HashMap存储参数,仍然会出现相同的报错。


问题根因

这个报错和你用HashMap还是自定义对象存参数没有关系,核心问题出在你直接持久化了Spring Data内置的Pageable对象:

  • Pageable内部会持有Sort.Order类型的排序属性,而org.springframework.data.domain.Sort.Order类没有公开的无参构造方法
  • Spring Data MongoDB反序列化文档成Java实体时,默认通过反射调用类的无参构造创建实例,找不到对应构造方法就会抛出你看到的NoSuchMethodException
  • 移除pageable对象后,存入的所有属性都是自带无参构造的普通类型,反序列化流程正常,所以功能恢复。
修复方案

按可维护性优先级推荐以下方案:

  • 方案1:转换为自定义持久化POJO存储(最推荐,稳定性最高)
    Spring内置的Pageable/Sort本质是运行时传参用的对象,从设计上就不是为持久化场景准备的,不要直接存到数据库里。
    你可以自己定义普通的POJO类,只保留需要的分页、排序基础字段(都是基本类型、字符串等可正常序列化的类型,记得给类加无参构造、getter/setter),入库前把Pageable转成自定义POJO存,查询取出后再手动转回框架可用的Pageable对象即可。
    示例代码:

// 持久化用的分页参数类
public class PersistentPage {
private int pageNum;
private int pageSize;
private List sorts;

// 必须保留无参构造
public PersistentPage() {}
// 省略getter、setter

}

// 持久化用的排序参数类
public class PersistentSort {
private String field;
private String direction; // 存ASC/DESC字符串

public PersistentSort() {}
// 省略getter、setter

}

// 入库前转换
PersistentPage persistentPage = new PersistentPage();
persistentPage.setPageNum(pageable.getPageNumber());
persistentPage.setPageSize(pageable.getPageSize());
persistentPage.setSorts(pageable.getSort().stream().map(order -> {
PersistentSort sort = new PersistentSort();
sort.setField(order.getProperty());
sort.setDirection(order.getDirection().name());
return sort;
}).toList());
params.put("pageable", persistentPage);

// 查询后转回Pageable
Sort querySort = Sort.by(persistentPage.getSorts().stream()
.map(s -> new Sort.Order(Sort.Direction.valueOf(s.getDirection()), s.getField()))
.toList());
Pageable queryPageable = PageRequest.of(persistentPage.getPageNum(), persistentPage.getPageSize(), querySort);

- **方案2:序列化为JSON字符串存储(适合动态参数场景)**
如果你的`inputData`是不需要作为查询条件、只需要整存整取的动态参数,可以直接把整个参数Map序列化为JSON字符串后存入文本字段,查询时取出字符串再手动反序列化为业务对象,完全绕过MongoDB默认的POJO反序列化逻辑,就不会触发构造函数找不到的问题。
- **不推荐方案:自定义反序列化器**
你也可以通过给Jackson配置MixIn注解、给MongoDB注册`Pageable`/`Sort`专属编解码器的方式让框架支持直接反序列化这两个类,但这种实现和Spring Data版本强绑定,后续框架升级很容易出现兼容问题,维护成本很高,非必要不选。

---
内容的提问来源于stack exchange,提问作者daph111
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 23:27:28