Jackson用Feign无法反序列化Spring的org.springframework.data.domain.Sort

Eri*_*rik 4 java spring-boot spring-cloud-feign feign openfeign

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

  • Spring Boot:2.3.3.发布
  • Spring Cloud Feign:2.2.5.RELEASE

com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造实例org.springframework.data.domain.Sort(不存在创建者,如默认构造函数):无法从[来源:(BufferedReader);的对象值(不基于委托或基于属性的创建者)反序列化;行: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);
  }

}
Run Code Online (Sandbox Code Playgroud)

客户本身:

public interface TelematicsClient {

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

}
Run Code Online (Sandbox Code Playgroud)

当调用这个我得到:

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)

Run Code Online (Sandbox Code Playgroud)

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

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

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

Lu5*_*u55 18

如果您使用自动配置的 Feign 客户端,您可以通过打开相应的配置属性来遵循Spring Cloud OpenFeign 文档:

您可以考虑启用 Jackson 模块来支持 org.springframework.data.domain.Pageorg.springframework.data.domain.Sort解码。

feign.autoconfiguration.jackson.enabled=true
Run Code Online (Sandbox Code Playgroud)


Eri*_*rik 11

找到了答案。

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.
Run Code Online (Sandbox Code Playgroud)