如何使用RestTemplate调用返回含Page对象的REST API
解决Spring Data Page类型Jackson反序列化问题
问题场景
使用RestTemplate调用返回分页数据的REST API时,遇到Jackson反序列化错误,无法构造org.springframework.data.domain.Page实例。核心错误信息:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.data.domain.Page` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 12] (through reference chain: net.code.sample.ReportResponse["reports"])
API响应的核心结构:
{ "reports": { "content": [...], "pageable": {...}, "totalElements": 321, "totalPages": 4, ... } }
当前客户端代码中,ReportResponse类直接使用抽象类Page<Product>作为字段,导致Jackson无法完成实例化。
错误原因
org.springframework.data.domain.Page是抽象类,没有默认构造器或Jackson可识别的创建逻辑,无法直接完成反序列化。必须指定具体的实现类(如PageImpl或自定义子类),并确保Jackson能正确映射JSON字段到类的构造参数。
解决方案
1. 修改ReportResponse类,替换抽象Page为具体实现类
将ReportResponse中的Page<Product>字段改为自定义的CustomPageImpl<Product>,并调整构造器参数类型:
@Data @Builder @FieldDefaults(level = AccessLevel.PRIVATE) public class ReportResponse implements Serializable { CustomPageImpl<Product> reportData; @JsonCreator public ReportResponse(@JsonProperty("reports") CustomPageImpl<Product> reportData) { this.reportData = reportData; } }
注:移除不必要的
CustomPageImpl继承,ReportResponse作为外层包装类无需继承分页实现类。
2. 修正CustomPageImpl的构造器逻辑
确保CustomPageImpl的@JsonCreator构造器正确使用JSON中的分页参数,而非硬编码值:
public class CustomPageImpl<T> extends PageImpl<T> { @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) public CustomPageImpl(@JsonProperty("content") List<T> content, @JsonProperty("number") int number, @JsonProperty("size") int size, @JsonProperty("totalElements") long totalElements, @JsonProperty("pageable") JsonNode pageable, @JsonProperty("last") boolean last, @JsonProperty("totalPages") int totalPages, @JsonProperty("sort") JsonNode sort, @JsonProperty("numberOfElements") int numberOfElements) { // 用传入的参数构建正确的Pageable对象 Pageable pageRequest = PageRequest.of(number, size); // 调用父类构造器传入完整分页参数 super(content, pageRequest, totalElements); } // 保留其他构造器 public CustomPageImpl(List<T> content, Pageable pageable, long total) { super(content, pageable, total); } public CustomPageImpl(List<T> content) { super(content); } public CustomPageImpl() { super(new ArrayList<>()); } }
3. 确保RestTemplate的Jackson配置正确
如果使用Spring Boot,默认RestTemplate已配置Jackson消息转换器;若需自定义,可添加如下配置确保分页类型被正确处理:
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setObjectMapper(new ObjectMapper() .registerModule(new ParameterNamesModule()) .registerModule(new Jdk8Module()) .registerModule(new JavaTimeModule())); restTemplate.getMessageConverters().add(0, converter); return restTemplate; }
验证修改
重新调用接口后,Jackson可将reports节点的JSON数据正确反序列化为CustomPageImpl<Product>实例,获取完整的分页元数据和内容列表。
内容的提问来源于stack exchange,提问作者Nital
相关产品推荐
相关产品推荐

