Skip to content

FeignHttpMessageConverters concurrency issue #1307

@alianman

Description

@alianman

Describe the bug
When mutiple concurrent threads call the org.springframework.cloud.openfeign.support.FeignHttpMessageConverters#getConverters method on a non-initialized class, some non-initialized converters could be returned. This leads to similar exceptions when processing requests/responses. After the class is initialized, no exceptions are thrown.

feign.codec.EncodeException: Could not write request: no suitable HttpMessageConverter found for request type [com.MyClass]
	at org.springframework.cloud.openfeign.support.SpringEncoder.encodeWithMessageConverter(SpringEncoder.java:168)
	at org.springframework.cloud.openfeign.support.SpringEncoder.encode(SpringEncoder.java:110)
	at org.springframework.cloud.openfeign.support.PageableSpringEncoder.encode(PageableSpringEncoder.java:105)
	at feign.RequestTemplateFactoryResolver$BuildEncodedTemplateFromArgs.resolve(RequestTemplateFactoryResolver.java:274)
	at feign.RequestTemplateFactoryResolver$BuildTemplateByResolvingArgs.create(RequestTemplateFactoryResolver.java:107)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:48)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:104)
	at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory$1.proceed(FeignCachingInvocationHandlerFactory.java:66)
	at org.springframework.cache.interceptor.CacheInterceptor.lambda$invoke$0(CacheInterceptor.java:54)
	at org.springframework.cache.interceptor.CacheAspectSupport.invokeOperation(CacheAspectSupport.java:424)
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:410)
	at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
	at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory.lambda$create$0(FeignCachingInvocationHandlerFactory.java:53)
	at jdk.proxy2/jdk.proxy2.$Proxy166.list(Unknown Source)
	... 189 filtered

java.lang.IllegalArgumentException: 'messageConverters' must not contain null elements
	at org.springframework.util.Assert.noNullElements(Assert.java:436)
	at org.springframework.web.client.HttpMessageConverterExtractor.<init>(HttpMessageConverterExtractor.java:78)
	at org.springframework.web.client.HttpMessageConverterExtractor.<init>(HttpMessageConverterExtractor.java:71)
	at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:56)
	at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:62)
	at feign.optionals.OptionalDecoder.decode(OptionalDecoder.java:38)
	at feign.InvocationContext.decode(InvocationContext.java:121)
	... 201 more
Wrapped by: <#64f634dc> feign.codec.DecodeException: 'messageConverters' must not contain null elements
	at feign.InvocationContext.decode(InvocationContext.java:125)
	at feign.InvocationContext.proceed(InvocationContext.java:94)
	at feign.ResponseHandler.handleResponse(ResponseHandler.java:69)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:109)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:53)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:104)
	at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory$1.proceed(FeignCachingInvocationHandlerFactory.java:66)
	at org.springframework.cache.interceptor.CacheInterceptor.lambda$invoke$0(CacheInterceptor.java:54)
	at org.springframework.cache.interceptor.CacheAspectSupport.invokeOperation(CacheAspectSupport.java:424)
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:410)
	at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
	at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory.lambda$create$0(FeignCachingInvocationHandlerFactory.java:53)
	at jdk.proxy2/jdk.proxy2.$Proxy166.list(Unknown Source)
	... 172 filtered

Workaround

Current workaround is declaring own converters bean and call initialization explicitly at application startup:

    @Bean
    @ConditionalOnMissingBean
    public FeignHttpMessageConverters feignHttpMessageConverters(
            ObjectProvider<HttpMessageConverter<?>> messageConverters,
            ObjectProvider<HttpMessageConverterCustomizer> customizers) {
        var feignHttpMessageConverters = new FeignHttpMessageConverters(messageConverters, customizers);
        // init converters
        feignHttpMessageConverters.getConverters();
        return feignHttpMessageConverters;
    }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions