spring-cloud / spring-cloud-stream

Framework for building Event-Driven Microservices
http://cloud.spring.io/spring-cloud-stream
Apache License 2.0
1.01k stars 613 forks source link

Function Binder can NOT support Kotlin DSL #2025

Open dipengfei opened 4 years ago

dipengfei commented 4 years ago

Dear Spring Cloud Stream Team,

I'm trying to practice Spring Cloud Stream with Kotlin, and below code works well as a simple producer,

@SpringBootApplication
class ProducerApplication

fun main(args: Array<String>) {
    runApplication<ProducerApplication>(*args)
}

@Configuration
class SourceConfig {

    @Bean
    fun productSource(): Supplier<Flux<Product>> = Supplier {
        Flux.interval(Duration.ofSeconds(1)).map {
            Product(
                ......
            )
        }.onBackpressureDrop()
    }

}

And the application.properties is also quite simple,

server.port=0
spring.cloud.stream.bindings.productSource-out-0.destination=products

The entire project can be found here.

But if I switch the bean configuration style from @Bean annotation to Kotlin DSL, it doesn't work, the code looks like,

@SpringBootApplication
class ProducerApplication

fun main(args: Array<String>) {
    runApplication<ProducerApplication>(*args) {
        addInitializers(
            beans {
                bean(name = "productSource") {
                    Supplier {
                        Flux.interval(Duration.ofSeconds(1)).map {
                            Product(
                                ......
                           )
                        }.onBackpressureDrop()
                    }
                }
            }
        )
    }
}

and below exception occurred,

2020-10-05 22:49:50.468 ERROR 49982 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'productSource' defined in class path resource [me/danielpf/rmkt/producer/SourceConfig.class]: @Bean definition illegally overridden by existing bean definition: Root bean: class [java.util.function.Supplier]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.isOverriddenByExistingDefinition(ConfigurationClassBeanDefinitionReader.java:329) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:205) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:62) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
    at me.danielpf.rmkt.producer.ProducerApplicationKt.main(ProducerApplication.kt:58) ~[main/:na]

I was doing some debug and found the issue should has something to do with FunctionConfiguration, in method extractPollableAnnotation, it seems the source object is always null under Kotlin DSL mode.

May I know if it's possible to enhance it to support Kotlin DSL? Thanks in advance.

olegz commented 4 years ago

Sure, we'll take a look. Thanks for reporting

olegz commented 3 years ago

@dmittriy13 in case you're interested to look at something Kotlin-related

This is most likely s-c-function issue. Let me know if you can tackle it

dmittriy13 commented 3 years ago

@dmittriy13 in case you're interested to look at something Kotlin-related

This is most likely s-c-function issue. Let me know if you can tackle it

I can watch it on the weekend