API request and response:
Request: http://localhost:5555/api/products?page=1&size=100
Response:
{
"reports": {
"content": [
{
"productCatTx": "ERROR_product",
"productValTx": "000",
"productShrtDescTx": "NO_ERROR",
"productLongDescTx": "No Error in response"
},
{
"productCatTx": "ERROR_product",
"productValTx": "010",
"productShrtDescTx": "PRODUCT_ACCEPTED",
"productLongDescTx": "Product Accepted"
}
],
"pageable": {
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"pageNumber": 0,
"pageSize": 100,
"unpaged": false,
"paged": true
},
"totalElements": 321,
"totalPages": 4,
"last": false,
"size": 100,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"numberOfElements": 100,
"first": true,
"empty": false
}
}
Client REST API call from another project:
@GetMapping("/paginatedWResponseData")
public void getProductsWResponseData() {
RestTemplate restTemplate = new RestTemplate();
String resourceUrl = "http://localhost:5555/api/products?page=1&size=100";
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(resourceUrl)
.queryParam("page", 1)
.queryParam("size", 100);
ResponseEntity<ReportResponse> responseEntity = restTemplate.exchange(uriBuilder.toUriString(),
HttpMethod.GET, null, ReportResponse.class);
System.out.println(responseEntity);
}
ReportResponse.java
@Data
@Builder
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ReportResponse extends CustomPageImpl implements Serializable {
Page<Product> reportData;
@JsonCreator
public ReportResponse(@JsonProperty("reports") Page<Product> reportData) {
super(reportData.getContent());
this.reportData = reportData;
}
}
CustomPageImpl.java
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) {
super(content, PageRequest.of(number, 1), 10);
}
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<>());
}
}
Error:
2023-08-24T13:58:53.372-04:00 ERROR 20304 --- [nio-5656-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.data.domain.Page]] with root cause
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"])
The stacktrace is telling you that Jackson library can't create a org.springframework.data.domain.Page
instance because it has no constructor, and it makes sense because is an interface.
I think what you actually need is adjust ReportResponse
to receive a CustomPageImpl
instance as argument in its constructor. Additionally you could also get rid of inheritance like this:
@Data
@Builder
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ReportResponse implements Serializable {
private final CustomPageImpl<Product> reportData;
@JsonCreator
public ReportResponse(@JsonProperty("reports") CustomPageImpl<Product> reportData) {
this.reportData = reportData;
}
public CustomPageImpl<Product> getReportData() {
return this.reportData;
}
}