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
// 必须保留无参构造 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

