【问题标题】:Jackson with Feign can't deserialized Spring's org.springframework.data.domain.SortJackson 和 Feign 无法反序列化 Spring 的 org.springframework.data.domain.Sort
【发布时间】:2021-01-03 13:40:09
【问题描述】:

问题:一个假装客户端,对返回 Page<T> 的 Spring Boot Rest API 进行 API 调用,无法反序列化该页面的 sort 属性。

  • Spring Boot:2.3.3.Release
  • Spring Cloud Feign:2.2.5.RELEASE

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 不能 构造org.springframework.data.domain.Sort 的实例(没有 创建者,如默认构造函数,存在):无法反序列化 [来源: (缓冲读取器);行:1,列:238](通过参考链: org.springframework.cloud.openfeign.support.PageJacksonModule$SimplePageImpl["sort"])

不知道为什么注册的PageJacksonModule 似乎不支持这一点。

给定一个手动配置的 Feign 客户端:

public class TelematicsConfig {

  private String host;

  ObjectMapper provideObjectMapper() {
    return new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .setPropertyNamingStrategy(SnakeCaseStrategy.SNAKE_CASE)
        .registerModule(new PageJacksonModule());
  }

  @Bean
  TelematicsClient provideTelematicsClient() {
    return Feign.builder()
        .client(new OkHttpClient())
        .encoder(new JacksonEncoder(provideObjectMapper()))
        .decoder(new JacksonDecoder(provideObjectMapper()))
        .logger(new Slf4jLogger(TelematicsClient.class))
        .logLevel(Logger.Level.FULL)
        .target(TelematicsClient.class, host);
  }

}

客户本身:

public interface TelematicsClient {

  @RequestLine("GET /api/v1/telematics/devices")
  Page<TelematicsDevice> getDevices();

}

当调用它时,我得到:

2020-09-16 12:38:49.707 ERROR 96244 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException: Cannot construct instance of `org.springframework.data.domain.Sort` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (BufferedReader); line: 1, column: 238] (through reference chain: org.springframework.cloud.openfeign.support.PageJacksonModule$SimplePageImpl["sort"]) reading GET http://localhost:8081/api/v1/telematics/devices] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.data.domain.Sort` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (BufferedReader); line: 1, column: 238] (through reference chain: org.springframework.cloud.openfeign.support.PageJacksonModule$SimplePageImpl["sort"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1611)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1077)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1320)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:331)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:164)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:535)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:419)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1310)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:331)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:164)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3463)
    at feign.jackson.JacksonDecoder.decode(JacksonDecoder.java:61)

任何关于为什么这不起作用的见解将不胜感激。

编辑:以下类似乎暗示支持排序,不是吗?

https://github.com/spring-cloud/spring-cloud-openfeign/blob/master/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageJacksonModule.java#L69

【问题讨论】:

    标签: java spring-boot spring-cloud-feign feign openfeign


    【解决方案1】:

    如果您使用自动配置的 Feign 客户端,您可以通过打开相应的配置属性来关注Spring Cloud OpenFeign docs

    您可以考虑启用 Jackson Modules 以获得支持 org.springframework.data.domain.Pageorg.springframework.data.domain.Sort解码。

    feign.autoconfiguration.jackson.enabled=true
    

    【讨论】:

    • 哦,太好了!我在文档中错过了这个。这似乎应该是默认设置,如果还没有的话。
    【解决方案2】:

    找到答案了。

    https://github.com/spring-cloud/spring-cloud-openfeign/blob/master/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SortJacksonModule.java

        return new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .setPropertyNamingStrategy(SnakeCaseStrategy.SNAKE_CASE)
            .registerModule(new PageJacksonModule())
            .registerModule(new SortJacksonModule()); // <-- This.  duh.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-03
      • 2020-05-08
      • 2015-10-02
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      • 1970-01-01
      • 2020-01-09
      相关资源
      最近更新 更多