I'm running into a scenario where I need to define a one-off @FeignClient for a third party API. In this client I'd like to use a custom Jackson ObjectMapper that differs from my @Primary one. I know it is possible to override spring's feign configuration defaults however it is not clear to me how to simply override the ObjectMapper just by this specific client.
Per the documentation, you can provide a custom decoder for your Feign client as shown below.
Feign Client Interface:
@FeignClient(value = "foo", configuration = FooClientConfig.class)
public interface FooClient{
//Your mappings
}
Feign Client Custom Configuration:
@Configuration
public class FooClientConfig {
@Bean
public Decoder feignDecoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
public ObjectMapper customObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
//Customize as much as you want
return objectMapper;
}
}
return new JacksonDecoder(customObjectMapper());
–
Riemann follow @NewBie`s answer, i can give the better one...
@Bean
public Decoder feignDecoder() {
return new JacksonDecoder();
}
if you want use jackson message converter in feign client, please use JacksonDecoder, because SpringDecoder will increase average latency of feignclient call in production.
<!-- feign-jackson decoder -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>10.1.0</version>
</dependency>
@NewBie's answer has serious performance problems. During the new HttpMessageConverters
process, loadclass will be performed, resulting in a large number of thread block. If you have used this code, please modify it as follows:
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
change to
HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;
You can use JMeter and Arthas to reproduce this phenomenon, and the modified program has been greatly improved.
you can use SpringDecoder and SpringEncoder.
public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters)
is deprecated. you should use another constructor:
public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters,
ObjectProvider<HttpMessageConverterCustomizer> customizers)
for example:
@Bean
public Decoder feignDecoder(ObjectProvider<HttpMessageConverterCustomizer> customizers) {
// HttpMessageConverter<?> jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
// HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
var httpMessageConverters = new HttpMessageConverters();
return new ResponseEntityDecoder(new SpringDecoder(() -> httpMessageConverters, customizers));
}
@Bean
public Encoder feignEncoder() {
var httpMessageConverters = new HttpMessageConverters();
return new SpringEncoder(() -> httpMessageConverters);
}
if you want to write a decode time customizer, then you can wright like this:
@Component
public class HttpMessageCustomizer implements HttpMessageConverterCustomizer {
@Override
public void accept(List<HttpMessageConverter<?>> httpMessageConverters) {
//customizing
}
@Override
public Consumer<List<HttpMessageConverter<?>>> andThen(Consumer<? super List<HttpMessageConverter<?>>> after) {
return HttpMessageConverterCustomizer.super.andThen(after);
}
}
Define a custom decoder as below, annotated with @Configuration
and set as parameter for the feign client interface, configuration = CustomFeignClientConfig.class
@Configuration
public class CustomFeignClientConfig {
@Bean
public Decoder feignDecoder() {
return (response, type) -> {
String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
JavaType javaType = TypeFactory.defaultInstance().constructType(type);
return new ObjectMapper().readValue( bodyStr, javaType);
};
}
}
© 2022 - 2024 — McMap. All rights reserved.
HttpMessageConverters
object that Spring MVC uses. Configuring it the normal Spring Boot way should 'just work' (thought I haven't tried it myself). docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… – LorinelorinerSpringDecoder
bean using the doc link a previously posted and mess with it there. – Lorineloriner