Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenFeign doesn't work with kotlin suspend method #661

Open
XhstormR opened this issue Jan 8, 2022 · 6 comments
Open

OpenFeign doesn't work with kotlin suspend method #661

XhstormR opened this issue Jan 8, 2022 · 6 comments
Labels

Comments

@XhstormR
Copy link

XhstormR commented Jan 8, 2022

I have an API interface where the methods are kotlin suspend methods:

@FeignClient(path = "/api/masker", contextId = "MaskerApi", name = Const.SERVICE, configuration = [FeignConfig::class])
interface MaskerApi {

    @PostMapping("/mask")
    suspend fun mask(
        @Valid @RequestBody maskRequest: MaskRequest,
    ): RestResponse<List<CharSequence>>

    @PostMapping("/matches")
    suspend fun matches(
        @Valid @RequestBody maskRequest: MaskRequest,
    ): RestResponse<List<Boolean>>
}

But when I run the program, the program throws an exception:

Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.lang.Object io.github.xhstormr.masker.web.api.masker.MaskerApi.matches(io.github.xhstormr.masker.model.masker.MaskRequest,kotlin.coroutines.Continuation)
Warnings:
- 
	at feign.Util.checkState(Util.java:121) ~[feign-core-11.7.jar:na]
	at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:142) ~[feign-core-11.7.jar:na]
	at org.springframework.cloud.openfeign.support.SpringMvcContract.parseAndValidateMetadata(SpringMvcContract.java:193) ~[spring-cloud-openfeign-core-3.1.0.jar:3.1.0]
	at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:65) ~[feign-core-11.7.jar:na]
	at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:151) ~[feign-core-11.7.jar:na]
	at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:49) ~[feign-core-11.7.jar:na]
	at feign.Feign$Builder.target(Feign.java:268) ~[feign-core-11.7.jar:na]
	at org.springframework.cloud.openfeign.DefaultTargeter.target(DefaultTargeter.java:30) ~[spring-cloud-openfeign-core-3.1.0.jar:3.1.0]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.loadBalance(FeignClientFactoryBean.java:373) ~[spring-cloud-openfeign-core-3.1.0.jar:3.1.0]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:421) ~[spring-cloud-openfeign-core-3.1.0.jar:3.1.0]
	at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:396) ~[spring-cloud-openfeign-core-3.1.0.jar:3.1.0]
	at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:235) ~[spring-cloud-openfeign-core-3.1.0.jar:3.1.0]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1249) ~[spring-beans-5.3.14.jar:5.3.14]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191) ~[spring-beans-5.3.14.jar:5.3.14]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.14.jar:5.3.14]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.14.jar:5.3.14]
	... 28 common frames omitted

This kotlin.coroutines.Continuation parameter is generated by the kotlin compiler at compile time, so I can't modify this parameter, how can I tell FeignClient to ignore this Continuation parameter?

@XhstormR
Copy link
Author

XhstormR commented Jan 12, 2022

When I make a successful call to make an http request, but it fails when converting the http call result json into an object. When I remove the suspend modifier in the method, try again and it will be successful.

java.lang.IllegalStateException: Failed to execute ApplicationRunner
   at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:761) ~[spring-boot-2.6.2.jar:2.6.2]
   at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:748) ~[spring-boot-2.6.2.jar:2.6.2]
   at org.springframework.boot.SpringApplication.run(SpringApplication.java:309) ~[spring-boot-2.6.2.jar:2.6.2]
   at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.2.jar:2.6.2]
   at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[spring-boot-2.6.2.jar:2.6.2]
   at io.github.xhstormr.masker.ApplicationKt.main(Application.kt:54) ~[main/:na]
Caused by: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class io.github.xhstormr.masker.model.response.RestResponse (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; io.github.xhstormr.masker.model.response.RestResponse is in unnamed module of loader 'app')
   at io.github.xhstormr.masker.web.api.masker.MaskerApi.maskSync(MaskerApi.kt:32) ~[main/:na]
   at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710) ~[na:na]
   at feign.DefaultMethodHandler.invoke(DefaultMethodHandler.java:141) ~[feign-core-11.7.jar:na]
   at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100) ~[feign-core-11.7.jar:na]
   at com.sun.proxy.$Proxy116.maskSync(Unknown Source) ~[na:na]
   at io.github.xhstormr.masker.Application.init$lambda-0(Application.kt:45) ~[main/:na]
   at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:758) ~[spring-boot-2.6.2.jar:2.6.2]
   ... 5 common frames omitted

@OlgaMaciaszek
Copy link
Collaborator

Hello, @XhstormR. We have never introduced kotlin support in Spring Cloud OpenFeign, so there might be many Kotlin constructs that will not work. Putting the issue into ice-box as currently we are not working on Kotlin support.

@aSemy
Copy link

aSemy commented Sep 29, 2022

It looks like OpenFeign recently merged in support for Kotlin suspend functions OpenFeign/feign#1706. When that PR is released and spring-cloud-openfeign can update, will suspend functions 'just work'?

@OlgaMaciaszek
Copy link
Collaborator

We'll review it. If it requires only minimal changes, we'll possibly implement support here also. However, if it's more involved, then Kotlin support is currently not a priority. However, we would review a PR if it's submitted.

@XhstormR
Copy link
Author

OpenFeign 12.0 was released with support for Kotlin coroutines. By looking at the test case CoroutineFeignTest, we simply need to build the Client using CoroutineFeign to get invocation support for the Kotlin coroutine.

https://github.com/OpenFeign/feign/blob/master/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt#L148

@Alex-Schiff
Copy link

Since the Feign class and the CoroutineFeign class have nothing in common, it is not trivial to add this support to spring-cloud-openfeign. I think it is a better fit for https://github.com/spring-projects-experimental/spring-cloud-openfeign-async if that ever gets written.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants