英文:
Jackson with Feign can't deserialized Spring's org.springframework.data.domain.Sort
问题
问题:一个 Feign 客户端调用 Spring Boot Rest API 发出 API 调用,该调用返回一个 Page<T>
,但无法反序列化该页面的 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
的实例(没有默认构造函数等创建者):无法从对象值反序列化(没有委托或基于属性的创建者)[来源:(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);
}
}
客户端本身:
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)
对于为什么不起作用,任何见解都将不胜感激。
编辑:下面的类似乎暗示支持排序,是吗?
英文:
The problem: A feign client, making an API call to a Spring boot Rest API that returns a Page<T>
can't deserialize the sort
property of that page.
- Spring Boot: 2.3.3.Release
- Spring Cloud Feign: 2.2.5.RELEASE
> 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"])
Not sure why the registered PageJacksonModule
doesn't seem to support that.
Given a manually configured Feign client:
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);
}
}
The client itself:
public interface TelematicsClient {
@RequestLine("GET /api/v1/telematics/devices")
Page<TelematicsDevice> getDevices();
}
When invoking this I get:
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)
Any insights into why this isn't working would be greatly appreciated.
Edit: The following class seems to hint at support for sorting, no?
答案1
得分: 18
如果您使用自动配置的Feign客户端,您可以按照Spring Cloud OpenFeign文档中的说明,通过打开相应的配置属性:
> 您可以考虑启用Jackson模块以支持
> 对org.springframework.data.domain.Page
和
> org.springframework.data.domain.Sort
的解码。
>
> feign.autoconfiguration.jackson.enabled=true
英文:
If you use autoconfigured Feign client you can follow Spring Cloud OpenFeign docs by turning on corresponding configuration property:
> You may consider enabling Jackson Modules for the support
> org.springframework.data.domain.Page
and
> org.springframework.data.domain.Sort
decoding.
>
> feign.autoconfiguration.jackson.enabled=true
答案2
得分: 10
找到答案。
链接: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()); // <-- 就是这里。 显然。
英文:
Found the answer.
return new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setPropertyNamingStrategy(SnakeCaseStrategy.SNAKE_CASE)
.registerModule(new PageJacksonModule())
.registerModule(new SortJacksonModule()); // <-- This. duh.
答案3
得分: 0
尝试添加:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>3.1.3</version>
<scope>compile</scope>
</dependency>
英文:
try to add :
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>3.1.3</version>
<scope>compile</scope>
</dependency>
答案4
得分: 0
你可以通过添加openfeign-core
依赖来获取这些模块:
implementation "org.springframework.cloud:spring-cloud-openfeign-core"
但是在Spring Boot 3中,对于SortJacksonModule
,这种方法不再适用。
举例:
代码(Kotlin)
private val mapper = jacksonObjectMapper().registerModules(
PageJacksonModule(),
SortJacksonModule(),
JavaTimeModule(),
)
配置:
抛出此异常:
java.lang.NoClassDefFoundError: feign/codec/EncodeException at org.springframework.cloud.openfeign.support.SortJacksonModule.setupModule(SortJacksonModule.java:47)
解决方法
OpenFeign Spring团队正在等待投票,以便花时间解决此问题。请务必在此问题上投票:
https://github.com/spring-cloud/spring-cloud-openfeign/issues/675
英文:
You can get these modules by adding the openfeign-core dependency:
implementation "org.springframework.cloud:spring-cloud-openfeign-core"
But this doesn't work in Spring Boot 3 for the SortJacksonModule
anymore.
For example:
Code (Kotlin)
private val mapper = jacksonObjectMapper().registerModules(
PageJacksonModule(),
SortJacksonModule(),
JavaTimeModule(),
)
Config:
Throws this exception:
java.lang.NoClassDefFoundError: feign/codec/EncodeException
at org.springframework.cloud.openfeign.support.SortJacksonModule.setupModule(SortJacksonModule.java:47)
Resolution
The OpenFeign spring team are waiting for votes in order to spend the time to fix this issue. Make sure to vote on the issue here:
https://github.com/spring-cloud/spring-cloud-openfeign/issues/675
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论