spring-cloud/spring-cloud-openfeign

Spring Boot 3.2.4 (Cloud 2023.0.1) Cannot deserialize "pageable": "INSTANCE"

dienarvil opened this issue · 5 comments

Describe the bug

Rest Controller in server with Spring Boot 2.7.18:

image

If I consume that end point from application with Spring Boot 2.7.18 (Cloud 2021.0.5) Deserialization is correct.

If I consume that end point from application with Spring Boot 3.2.4 (Cloud 2023.0.1) Deserialization fails.

log trace:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of org.springframework.cloud.openfeign.support.PageJacksonModule$SimplePageable (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('INSTANCE')


If I create Page object with the constructor:

Page page = new PageImpl<>(build, PageRequest.of(0,2), 2);

Works perfectly in Spring 2.7.18 and Spring boot 3.2.4

Thank you !!

Hello @dienarvil, thanks for reporting the issue. Please provide a minimal, complete, verifiable example that reproduces the issue.

demo.zip

localhost:8080/testok -> feign call to ok end point with Page page = new PageImpl<>(build, PageRequest.of(0,2), 2);
and
localhost:8080/testko -> feign call to ko end point with Page page = new PageImpl<>(build, Pageable.unpaged(), 2);

I just stumbled upon the same symptom and dug in a bit.

The reported error happens when deserializing the following json:

{
  "content": [
    "foo"
  ],
  "pageable": "INSTANCE",   <== HERE
  "totalPages": 1,
  "totalElements": 1,
  "last": true,
  "size": 1,
  "number": 0,
  "sort": [],
  "numberOfElements": 1,
  "first": true,
  "empty": false
}

As @dienarvil noted, the json is generated by the following:

Page<String> page = new PageImpl<>(List.of("foo"));  // or usage of Pageable.unpaged()
String json = this.objectMapper.writeValueAsString(page);

// deserialize json will throw the exception

When serializing a PageImpl, if it doesn't specify the pageable parameter, it uses Pageable.unpaged().
SpringDataJacksonConfiguration from spring-data-commons registers a serializer for Unpaged which writes out the value INSTANCE. So, the generated json has pageable:"INSTANCE".

It is not the json format that spring-cloud-openfeign is expecting.
In v4.1.1, PageJacksonModule#SimplePageImpl added Pageable object parameter(#984) and the expected format is SimplePageable. The deserializer doesn't work for INSTANCE string from Unpaged.

Per spring-projects/spring-data-commons#3024, spring-data-commons v3.3 may produce a more stable json representation.

@dienarvil
For a fix, I suggest simply providing the page information(Pageable) rather than using Unpaged while creating PageImpl object. So, that the response json will be more conformed as an added benefit.

@dienarvil For a fix, I suggest simply providing the page information(Pageable) rather than using Unpaged while creating PageImpl object. So, that the response json will be more conformed as an added benefit.

Thanks for the advice, yeah, with "normal" pagination from a repository the problem will never arise.

Thanks again!!

Thanks for the analysis @ttddyy. Until this gets addressed better in Spring Data, we expect a proper Pageable object to be provided.