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<Article> 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 ?
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));
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With