【问题标题】:Error during Deserialization of PageImpl : Cannot construct instance of `org.springframework.data.domain.PageImpl`PageImpl 反序列化期间出错:无法构造 `org.springframework.data.domain.PageImpl` 的实例
【发布时间】:2019-05-03 07:58:05
【问题描述】:

问题是在使用带有 redis 缓存管理器的 Spring 缓存时,由于没有默认构造函数而无法反序列化 Spring Pageable 响应

使用的spring boot版本是2.1.4.RELEASE

使用序列化器的 Redis 配置类

@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();

}

我正在尝试使用 Spring 缓存和 Redis 作为缓存后端在 Redis 缓存中缓存 Spring REST API 页面结果响应

@GetMapping
@Cacheable("Article_Response_Page")
public Page<Article> findAll(Pageable pageable) {
    return articleRepository.findAll(pageable);
}

我可以看到页面使用 RedisSerializer.json() 序列化程序在 Redis 缓存中缓存为 JSON,但是在下一次调用时,当从缓存中读取数据时,我得到以下异常

 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]

我尝试为 PageImpl 提供一个自定义序列化程序,然后我得到了一个异常的 PageRequest 实现和 Sort 实现 Spring 'org.springframework.data.domain' 包的所有部分

必须有更好的方法来解决这个问题,我想知道在 spring 缓存中解决此类问题的最佳方法

这是迁移到 SPRING BOOT v2 后的 Jackson 错误吗?

【问题讨论】:

    标签: spring-boot spring-cache jackson2 fasterxml spring-data-commons


    【解决方案1】:

    您可以使用 PageImpl 的包装器,然后:

    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);
        }
    }
    

    【讨论】:

    • 这会导致其他错误:无法构造org.springframework.data.domain.Pageable 的实例(没有创建者,如默认构造,存在):抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,要么包含其他类型信息
    【解决方案2】:

    我暂时通过使用 JAVA 序列化程序解决了这个问题,但想知道如何在打开 JSON 值序列化程序的情况下解决这个问题

    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
            .serializeValuesWith(
                    RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.java()));
    

    【讨论】:

      【解决方案3】:

      我正在使用 Spring Boot 2.6.2。尝试向返回页面的 Spring Boot 服务发出 http get 请求时遇到相同的错误。我刚刚通过在我的 feign 客户端中添加属性 feign.autoconfiguration.jackson.enabled=true 来解决它。我正在使用 spring-cloud-starter-openfeign。

      https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-data-support

      【讨论】:

        【解决方案4】:

        我在创建一个简单的 REST 接口时遇到了同样的问题。我的解决方案是扩展 PageImpl 并指定所需的 JsonProperties,同时明确忽略其他的:

        @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());
            }
        }
        

        您可以按照以下方式编写控制器:

        @GetMapping
        @Cacheable("Article_Response_Page")
        public RestPage<Article> findAll(Pageable pageable) {
            return new RestPage<>(articleRepository.findAll(pageable));
        }
        

        【讨论】:

          猜你喜欢
          • 2019-02-28
          • 2019-10-16
          • 1970-01-01
          • 1970-01-01
          • 2019-07-06
          • 2021-04-25
          • 2013-01-13
          • 2020-11-26
          • 2019-09-22
          相关资源
          最近更新 更多