'Error during Deserialization of PageImpl : Cannot construct instance of `org.springframework.data.domain.PageImpl`
Issue is when using Spring cache with redis cache manager, not able to deserializer Spring Pageable response due to no default constructor
The spring boot version used is 2.1.4.RELEASE
Redis config class that uses the serializer
@Bean
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
redisCacheConfiguration.usePrefix();
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
.cacheDefaults(redisCacheConfiguration).build();
}
I am trying to cache spring REST API Page result response in Redis cache using Spring cache and Redis as a cache backend
@GetMapping
@Cacheable("Article_Response_Page")
public Page<Article> findAll(Pageable pageable) {
return articleRepository.findAll(pageable);
}
I am able to see the Page getting cached as JSON in Redis cache using RedisSerializer.json() serializer but during the next call when the data is read from the cache I get the following exception
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot
construct instance of `org.springframework.data.domain.PageImpl` (no
Creators, like default construct, exist): cannot deserialize from Object
value (no delegate- or property-based Creator)
at [Source: (byte[])"
{"@class":"org.springframework.data.domain.PageImpl","content":
["java.util.Collections$UnmodifiableRandomAccessList",[]],"pageable":
{"@class":"org.springframework.data.domain.PageRequest","sort":{"@class":"org.springframework.data.domain.Sort","sorted":false,"unsorted":true,"empty":true},"offset":0,"pageSize":20,"pageNumber":0,"paged":true,"unpaged":false},"totalPages":0,"totalElements":0,"last":true,"size":20,"number":0,"sort":{"@class":"org.springframework.data.domain.Sort","sorted":false,"uns"[truncated 73 bytes]; line: 1, column: 54]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.8.jar:2.9.8]
I tried giving a custom serializer for PageImpl then I got an exception for PageRequest implementation and Sort implementation all part of Spring 'org.springframework.data.domain' package
There must be a better way to solve this and I like to know the best approach to solve this kind of issue in spring cache
Is this a Jackson bug after moving to SPRING BOOT v2 ?
Solution 1:[1]
You can use wrapper of PageImpl and then:
public class PageImpl<T> extends org.springframework.data.domain.PageImpl<T> {
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public PageImpl(@JsonProperty("content") List<T> content,
@JsonProperty("number") int page,
@JsonProperty("size") int size,
@JsonProperty("totalElements") long total) {
super(content, PageRequest.of(page, size), total);
}
}
Solution 2:[2]
I fixed the issue for time being by using JAVA serializer but like to know how this can be fixed with JSON value serializer turned on
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.java()));
Solution 3:[3]
I'm using spring boot 2.6.2. Got the same error trying to make an http get request to a spring boot service that returns a Page. I just solved it by adding the property feign.autoconfiguration.jackson.enabled=true in my feign client. I'm using spring-cloud-starter-openfeign.
https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-data-support
Solution 4:[4]
I had the same Problem when creating a simple REST interface. The solution for me was to extend PageImpl and specify the required JsonProperties while explicitly ignoring the other ones:
@JsonIgnoreProperties(ignoreUnknown = true, value = {"pageable"})
public class RestPage<T> extends PageImpl<T> {
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public RestPage(@JsonProperty("content") List<T> content,
@JsonProperty("number") int page,
@JsonProperty("size") int size,
@JsonProperty("totalElements") long total) {
super(content, PageRequest.of(page, size), total);
}
public RestPage(Page<T> page) {
super(page.getContent(), page.getPageable(), page.getTotalElements());
}
}
You can than write your Controller along the lines of:
@GetMapping
@Cacheable("Article_Response_Page")
public RestPage<Article> findAll(Pageable pageable) {
return new RestPage<>(articleRepository.findAll(pageable));
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Anton |
| Solution 2 | Tan mally |
| Solution 3 | acron.bn |
| Solution 4 | attalos |
