spring-projects / spring-integration

Spring Integration provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns (EIP)
http://projects.spring.io/spring-integration/
Apache License 2.0
1.54k stars 1.11k forks source link

Cannot use Kotlin with Spring Integration 5.0.4 while Java still working (Integration Flows DSL) [INT-4456] #8397

Closed spring-operator closed 6 years ago

spring-operator commented 6 years ago

FAGIM SADYKOV opened INT-4456 and commented

kotlin 1.2.40 spring integration 5.0.4

(was working with 1.2.30 + 4.* spring integration)

try to create integration flow config (several ways):


 ...
 .route
{ m : MyClass -> m.key }

 ...
 .route ( MyClass::class.java,
{ m : MyClass -> m.key }
)
 ...
 //even
 .route<MyClass,String>( object:java.lang.functions.Function<MyClass,String> ...)

All those notations compiled but fail at run time while Spring Integration cannot find method to use as Route.

If config is rewritten in Java - all working.

One thing is that Kotlins lambdas are not of synthetic class while Java's are, so Spring Integration not sees them as lambdas.

At another hand it worked before and some DSL things as transform and some other still work with Kotlin lambdas.

It can be avoided with explicit method name :


 .route (
{ m : MyClass -> m.key }
,"apply")

While it's very ugly.

Does anyone knew solution except "apply" or shifting @Configuration with Sp Int to Java?


Affects: 5.0.4

Referenced from: pull request https://github.com/spring-projects/spring-integration/pull/2430

spring-operator commented 6 years ago

FAGIM SADYKOV commented

At stack overflow https://stackoverflow.com/questions/50050876/cannot-create-kotlin-config-for-spring-integration-5-0-4-spring-5-0-5

spring-operator commented 6 years ago

FAGIM SADYKOV commented

At Kotlin tracker https://youtrack.jetbrains.com/issue/KT-24118

spring-operator commented 6 years ago

Artem Bilan commented

I would close it as Invalid, because Spring Integration doesn't advertise Kotlin support. But we are open for any suggestions and fixes.

We may help you, but you need to provide a minimal Spring Boot project to let us to play.

Thanks for understanding.

P.S. Since we don't provide an explicit Kotlin support, I don't consider this as critical, more over as bug.

spring-operator commented 6 years ago

FAGIM SADYKOV commented

Kotlin

package comdiv

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.integration.channel.DirectChannel
import org.springframework.integration.config.EnableIntegration
import org.springframework.integration.dsl.IntegrationFlows
import org.springframework.integration.dsl.Pollers
import org.springframework.integration.dsl.StandardIntegrationFlow
import org.springframework.integration.dsl.channel.MessageChannels
import org.springframework.integration.scheduling.PollerMetadata
import org.springframework.messaging.support.GenericMessage
import org.springframework.test.context.junit.jupiter.SpringExtension

@Configuration
@EnableIntegration
open class Config {

 @Bean(name = arrayOf(PollerMetadata.DEFAULT_POLLER))
 open fun poller() : PollerMetadata { // 11
 return Pollers.fixedDelay(1000).get()
 }
 @Bean open fun output() : DirectChannel? {
 return MessageChannels.direct("output").get()
 }
 @Bean
 open fun someFlow() = IntegrationFlows
 .from { -> GenericMessage("hello world") } //ok
 .transform{ it:String -> "++$it++"} //ok
 .route{s:String->"output"} // not working Found ambiguous parameter type [interface java.util.function.Function]
 //.route({s:String->"output"},"invoke") // working !!!
 //.route(Function<String, String> { "output" }) //not working !!! Found ambiguous parameter type [interface java.util.function.Function]
 //.route (Function<String, String> { "output" },"apply") // working

 .get()
}

@ExtendWith(SpringExtension::class)
@SpringBootTest(classes = [Config::class],webEnvironment = SpringBootTest.WebEnvironment.NONE)
class TryCreateIntegrationFlowTest {
 @Autowired
 lateinit var someFlow : StandardIntegrationFlow

 @Test
 fun canRunFlow(){
 someFlow.run { println("called")}
 }

}
spring-operator commented 6 years ago

FAGIM SADYKOV commented

POM


<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 [http://maven.apache.org/xsd/maven-4.0.0.xsd](https://maven.apache.org/xsd/maven-4.0.0.xsd)">
 <modelVersion>4.0.0</modelVersion>

<groupId>comdiv</groupId>
 <artifactId>kotlin-spring-integration-issue</artifactId>
 <version>1.0-SNAPSHOT</version>
 <properties>
 <kotlin.version>1.2.40</kotlin.version>
 <spring.version>5.0.5.RELEASE</spring.version>
 <spring-boot.version>2.0.0.RELEASE</spring-boot.version>
 <spring-integration.version>5.0.4.RElEASE</spring-integration.version>
 <junit.version>5.1.1</junit.version>
 <junit.runner.version>1.1.1</junit.runner.version>
 <surefire.version>2.19.1</surefire.version>
 </properties>

<dependencies>
 <dependency>
 <groupId>org.jetbrains.kotlin</groupId>
 <artifactId>kotlin-stdlib-jdk8</artifactId>
 <version>${kotlin.version}</version>
 </dependency>
 <dependency>
 <groupId>org.junit.jupiter</groupId>
 <artifactId>junit-jupiter-api</artifactId>
 <scope>test</scope>
 <version>${junit.version}</version>
 </dependency>
 <dependency>
 <groupId>org.junit.jupiter</groupId>
 <artifactId>junit-jupiter-engine</artifactId>
 <scope>test</scope>
 <version>${junit.version}</version>
 </dependency>
 <dependency>
 <groupId>org.junit.platform</groupId>
 <artifactId>junit-platform-surefire-provider</artifactId>
 <scope>test</scope>
 <version>${junit.runner.version}</version>
 </dependency>
 <dependency>
 <groupId>org.junit.platform</groupId>
 <artifactId>junit-platform-runner</artifactId>
 <scope>test</scope>
 <version>${junit.runner.version}</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>${spring.version}</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework.integration</groupId>
 <artifactId>spring-integration-core</artifactId>
 <version>${spring-integration.version}</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-test</artifactId>
 <version>${spring-boot.version}</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-test</artifactId>
 <version>5.0.4.RELEASE</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.jetbrains.kotlin</groupId>
 <artifactId>kotlin-reflect</artifactId>
 <version>${kotlin.version}</version>
 <scope>test</scope>
 </dependency>
 </dependencies>

<build>
 <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
 <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
 <plugins>
 <plugin>
 <artifactId>kotlin-maven-plugin</artifactId>
 <groupId>org.jetbrains.kotlin</groupId>
 <version>${kotlin.version}</version>
 <executions>
 <execution>
 <id>compile</id>
 <goals> <goal>compile</goal> </goals>
 </execution>
 <execution>
 <id>test-compile</id>
 <goals> <goal>test-compile</goal> </goals>
 </execution>
 </executions>
 </plugin>
 <plugin>
 <artifactId>maven-surefire-plugin</artifactId>
 <version>${surefire.version}</version>
 <dependencies>
 <dependency>
 <groupId>org.junit.platform</groupId>
 <artifactId>junit-platform-surefire-provider</artifactId>
 <version>${junit.runner.version}</version>
 </dependency>
 </dependencies>
 <configuration>
 <forkCount>0</forkCount>
 <reuseForks>true</reuseForks>
 <argLine>-Dfile.encoding=UTF-8</argLine>
 </configuration>
 </plugin>
 </plugins>
 </build>

</project>
spring-operator commented 6 years ago

FAGIM SADYKOV commented

https://github.com/comdiv/kotlin-spring-issue/blob/master/src/test/kotlin/comdiv/TryCreateIntegrationFlowTest.kt

spring-operator commented 6 years ago

FAGIM SADYKOV commented

Suggestion - most DSL commands "understands" Kotlin lambdas , while route (and may be somthing else) not.

So it good idea to detect "invoke" method and call it without explicit definition

spring-operator commented 6 years ago

Gary Russell commented

From my perspective, I would like the project to support Kotlin. We may have to push it to the 5.1 release due late summer, but we may be able to do it in a 5.0.x release if the changes are not too extensive.

spring-operator commented 6 years ago

Artem Bilan commented

See my answer on mentioned StackOverflow.

 

I don't mind to fix, but that's not support: we don't provide any extensions.

spring-operator commented 6 years ago

Gary Russell commented

I agree it would be better if Kotlin was more compliant and compatible, but that ship may have sailed.