diff --git a/basic/helloworld-groovy/src/main/groovy/org/springframework/integration/samples/helloworld/HelloWorldConfig.groovy b/basic/helloworld-groovy/src/main/groovy/org/springframework/integration/samples/helloworld/HelloWorldConfig.groovy index f572d18ed..f186de378 100644 --- a/basic/helloworld-groovy/src/main/groovy/org/springframework/integration/samples/helloworld/HelloWorldConfig.groovy +++ b/basic/helloworld-groovy/src/main/groovy/org/springframework/integration/samples/helloworld/HelloWorldConfig.groovy @@ -43,7 +43,7 @@ class HelloWorldConfig { @Bean MessageChannel outputChannel() { - new QueueChannel(10) + new QueueChannel() } @Bean diff --git a/basic/helloworld-kotlin/README.md b/basic/helloworld-kotlin/README.md new file mode 100644 index 000000000..ef6a70a9c --- /dev/null +++ b/basic/helloworld-kotlin/README.md @@ -0,0 +1,38 @@ +Hello World Sample +================== + +This is the Kotlin version of the helloworld Java sample using Kotlin DSL. This sample project contains 2 basic sample applications: + +* Hello World +* Poller Application + +## Hello World + +The Hello World application demonstrates a simple message flow represented by the diagram below: + + Message -> Channel -> ServiceActivator -> QueueChannel + +To run the sample simply execute **HelloWorldApp** in package **org.springframework.integration.samples.helloworld**. +You can also execute that class using the [Gradle](https://www.gradle.org): + + $ gradlew :helloworld-kotlin:runHelloWorldApp + +You should see the following output: + + INFO : org.springframework.integration.samples.helloworld.HelloWorldApp - ==> HelloWorldDemo: Hello World + +## Poller Application + +This simple application will print out the current system time twice every 20 seconds. + +More specifically, an **Inbound Channel Adapter** polls for the current system time 2 times every 20 seconds (20000 milliseconds). The resulting message contains as payload the time in milliseconds and the message is sent to a **Logging Channel Adapter**, which will print the time to the command prompt. + +To run the sample simply execute **PollerApp** in package **org.springframework.integration.samples.helloworld**. +You can also execute that class using the [Gradle](https://www.gradle.org): + + $ gradlew :helloworld-kotlin:runPollerApp + +You should see output like the following: + +[task-scheduler-1][org.springframework.integration.samples.helloworld] GenericMessage [payload=1763478785243, headers={id=8f93b18a-063a-5e9f-4708-2ed1d04a1566, timestamp=1763478785244}] +[task-scheduler-1][org.springframework.integration.samples.helloworld] GenericMessage [payload=1763478785248, headers={id=aa37e9c4-95d1-538c-a6cd-d400bb1474bf, timestamp=1763478785248}] diff --git a/basic/helloworld-kotlin/pom.xml b/basic/helloworld-kotlin/pom.xml new file mode 100644 index 000000000..2e8a454e7 --- /dev/null +++ b/basic/helloworld-kotlin/pom.xml @@ -0,0 +1,241 @@ + + + 4.0.0 + org.springframework.integration.samples + helloworld-kotlin + 7.0.0 + https://github.com/spring-projects/spring-integration-samples + + Spring IO + https://spring.io/projects/spring-integration + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + artembilan + Artem Bilan + artem.bilan@broadcom.com + + project lead + + + + garyrussell + Gary Russell + github@gprussell.net + + project lead emeritus + + + + markfisher + Mark Fisher + mark.ryan.fisher@gmail.com + + project founder and lead emeritus + + + + cppwfs + Glenn Renfro + glenn.renfro@broadcom.com + + project committer + + + + + scm:git:scm:git:git://github.com/spring-projects/spring-integration-samples.git + scm:git:scm:git:ssh://git@github.com:spring-projects/spring-integration-samples.git + https://github.com/spring-projects/spring-integration-samples + + + GitHub + https://github.com/spring-projects/spring-integration-samples/issues + + + + + org.jetbrains.kotlin + kotlin-stdlib + 2.2.21 + + + org.jetbrains.kotlin + kotlin-reflect + 2.2.21 + + + org.junit + junit-bom + 6.0.0 + import + pom + + + tools.jackson + jackson-bom + 3.0.0-rc9 + import + pom + + + com.fasterxml.jackson + jackson-bom + 2.20.0 + import + pom + + + org.springframework + spring-framework-bom + 7.0.0-SNAPSHOT + import + pom + + + org.springframework.integration + spring-integration-bom + 7.0.0-SNAPSHOT + import + pom + + + + + + org.apache.logging.log4j + log4j-core + 2.24.3 + compile + + + org.springframework.integration + spring-integration-core + compile + + + org.jetbrains.kotlin + kotlin-stdlib + compile + + + org.jetbrains.kotlin + kotlin-reflect + compile + + + org.hamcrest + hamcrest-library + 2.2 + test + + + org.mockito + mockito-core + 5.18.0 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.springframework.integration + spring-integration-test + test + + + org.apache.logging.log4j + log4j-core-test + 2.24.3 + test + + + org.awaitility + awaitility + 4.2.2 + test + + + org.assertj + assertj-core + 3.27.6 + test + + + org.junit.jupiter + junit-jupiter-engine + runtime + + + org.junit.platform + junit-platform-launcher + runtime + + + + 17 + + + + repo.spring.io.milestone + Spring Framework Maven Milestone Repository + https://repo.spring.io/milestone + + + repo.spring.io.snapshot + Spring Framework Maven Snapshot Repository + https://repo.spring.io/snapshot + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + 2.2.21 + + + -Xjsr305=strict + + + spring + + + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + 2.2.21 + + + + + + diff --git a/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloService.kt b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloService.kt new file mode 100644 index 000000000..d766202d9 --- /dev/null +++ b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloService.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +/** + * Simple POJO to be referenced from a Service Activator. + * + * @author Glenn Renfro + */ +class HelloService { + + fun sayHello(name: String) = "Hello $name" + +} diff --git a/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloWorldApp.kt b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloWorldApp.kt new file mode 100644 index 000000000..7a9c78d0f --- /dev/null +++ b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloWorldApp.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.apache.commons.logging.LogFactory +import org.springframework.context.annotation.AnnotationConfigApplicationContext +import org.springframework.messaging.MessageChannel +import org.springframework.messaging.PollableChannel +import org.springframework.messaging.support.GenericMessage + +/** + * Demonstrates a basic Message Endpoint that simply prepends a greeting + * ("Hello ") to an inbound String payload from a Message. + * + * @author Glenn Renfro + */ +object HelloWorldApp { + + private val logger = LogFactory.getLog(HelloWorldApp::class.java) + + @JvmStatic + fun main(args: Array) { + val context = AnnotationConfigApplicationContext(HelloWorldConfig::class.java) + val inputChannel = context.getBean("inputChannel", MessageChannel::class.java) + val outputChannel = context.getBean("outputChannel", PollableChannel::class.java) + inputChannel.send(GenericMessage("World")) + logger.info("==> HelloWorldDemo: ${outputChannel.receive(0)?.payload}") + context.close() + } + +} diff --git a/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloWorldConfig.kt b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloWorldConfig.kt new file mode 100644 index 000000000..bbe2c5efa --- /dev/null +++ b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/HelloWorldConfig.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.integration.channel.DirectChannel +import org.springframework.integration.channel.QueueChannel +import org.springframework.integration.config.EnableIntegration +import org.springframework.integration.dsl.integrationFlow +import org.springframework.messaging.MessageChannel + +/** + * Configuration for the HelloWorld integration flow using Kotlin DSL. + * + * @author Glenn Renfro + */ +@Configuration(proxyBeanMethods = false) +@EnableIntegration +class HelloWorldConfig { + + /** + * Creates the input channel for inbound messages. + * + * A [DirectChannel] is used for synchronous, immediate message delivery. + * Messages arriving on this channel are processed on the sender's thread + * without any buffering or queuing. + * + * @return A [DirectChannel] instance for synchronous inbound message delivery + */ + @Bean + fun inputChannel() = DirectChannel() + + /** + * Creates the output channel for outbound messages. + * + * A [QueueChannel] with default capacity provides asynchronous, + * buffered message delivery. Results from the integration flow are queued + * and available for downstream consumption. + * + * @return A [QueueChannel] instance with default capacity. + */ + @Bean + fun outputChannel() = QueueChannel() + + /** + * Creates the Hello World business service. + * + * [HelloService] implements the core greeting logic that transforms + * input messages into personalized greeting responses. + * + * @return A [HelloService] instance + */ + @Bean + fun helloService() = HelloService() + + /** + * Defines the main integration flow for message processing. + * + * @param inputChannel The synchronous input channel receiving messages + * @param outputChannel The asynchronous output channel for results + * @param helloService The service implementing the greeting logic + * @return An IntegrationFlow representing the complete message flow + */ + @Bean + fun helloWorldFlow(inputChannel: MessageChannel, outputChannel: MessageChannel, helloService: HelloService) = + integrationFlow(inputChannel) { + handle(helloService, "sayHello") + channel(outputChannel) + } +} diff --git a/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/PollerApp.kt b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/PollerApp.kt new file mode 100644 index 000000000..11980cbbf --- /dev/null +++ b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/PollerApp.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.springframework.context.annotation.AnnotationConfigApplicationContext + +/** + * Simple application that polls the current system time 2 times every + * 20 seconds (20000 milliseconds). + * + * The resulting message contains the time in milliseconds and the message + * is routed to a Logging Channel Adapter which will print the time to the + * command prompt. + * + * @author Glenn Renfro + */ +object PollerApp { + + @JvmStatic + fun main(args: Array) { + AnnotationConfigApplicationContext(PollerConfig::class.java) + } + +} diff --git a/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/PollerConfig.kt b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/PollerConfig.kt new file mode 100644 index 000000000..1e136dec2 --- /dev/null +++ b/basic/helloworld-kotlin/src/main/kotlin/org/springframework/integration/samples/helloworld/PollerConfig.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.integration.channel.NullChannel +import org.springframework.integration.config.EnableIntegration +import org.springframework.integration.dsl.integrationFlow +import org.springframework.integration.handler.LoggingHandler + +/** + * Configuration for the Poller integration flow using the Kotlin DSL. + * This flow polls for the current system time every 20 seconds and logs it. + * + * @author Glenn Renfro + */ +@Configuration(proxyBeanMethods = false) +@EnableIntegration +class PollerConfig { + + /** + * Defines a polling-based integration flow for periodic message generation. + * + * This flow demonstrates a time-triggered, scheduled message processing pattern. + * A message source generates timestamps at fixed intervals, logs the values, + * and discards them via the null channel. This is useful for monitoring, + * health checks, or triggering periodic processing logic. + * + * @return An IntegrationFlow that periodically generates and logs timestamps, then discards them. + */ + @Bean + fun pollerFlow() = + integrationFlow( + { System.currentTimeMillis() }, + { poller { it.fixedDelay(20000).maxMessagesPerPoll(2) } }) { + log(LoggingHandler.Level.INFO, "org.springframework.integration.samples.helloworld") + channel(NullChannel()) + } +} diff --git a/basic/helloworld-kotlin/src/main/resources/log4j2.xml b/basic/helloworld-kotlin/src/main/resources/log4j2.xml new file mode 100644 index 000000000..7545f857d --- /dev/null +++ b/basic/helloworld-kotlin/src/main/resources/log4j2.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/HelloServiceTests.kt b/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/HelloServiceTests.kt new file mode 100644 index 000000000..6b0ab5fd3 --- /dev/null +++ b/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/HelloServiceTests.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +/** + * Unit tests for HelloService. + * + * @author Glenn Renfro + */ +class HelloServiceTests { + + @Test + fun testSayHello() { + val service = HelloService() + val result = service.sayHello("World") + assertThat(result).isEqualTo("Hello World") + } + +} diff --git a/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/HelloWorldConfigTests.kt b/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/HelloWorldConfigTests.kt new file mode 100644 index 000000000..df5acb516 --- /dev/null +++ b/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/HelloWorldConfigTests.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.messaging.MessageChannel +import org.springframework.messaging.PollableChannel +import org.springframework.messaging.support.GenericMessage +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig + +/** + * Integration tests for HelloWorld flow. + * + * @author Glenn Renfro + */ +@SpringJUnitConfig(HelloWorldConfig::class) +class HelloWorldConfigTests { + + @Autowired + lateinit var inputChannel: MessageChannel + + @Autowired + lateinit var outputChannel: PollableChannel + + @Test + fun testHelloWorldFlow() { + inputChannel.send(GenericMessage("World")) + val message = outputChannel.receive(1000) + assertThat(message).isNotNull + assertThat(message?.payload).isNotNull + } + + @Test + fun testMultipleMessages() { + inputChannel.send(GenericMessage("Test1")) + inputChannel.send(GenericMessage("Test2")) + + val message1 = outputChannel.receive(1000) + assertThat(message1).isNotNull + assertThat(message1?.payload).isEqualTo("Hello Test1") + + val message2 = outputChannel.receive(1000) + assertThat(message2).isNotNull + assertThat(message2?.payload).isEqualTo("Hello Test2") + } + +} diff --git a/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/PollerConfigTests.kt b/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/PollerConfigTests.kt new file mode 100644 index 000000000..8b0dfe3de --- /dev/null +++ b/basic/helloworld-kotlin/src/test/kotlin/org/springframework/integration/samples/helloworld/PollerConfigTests.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2025-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.integration.samples.helloworld + +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.core.LoggerContext +import org.apache.logging.log4j.core.test.appender.ListAppender +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.integration.dsl.IntegrationFlow +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig +import java.time.Duration + + +/** + * Integration tests for Poller flow. + * Tests verify that the poller actually polls and produces messages. + * + * @author Glenn Renfro + */ +@SpringJUnitConfig(PollerConfig::class) +@DirtiesContext +class PollerConfigTests { + + @Autowired + lateinit var pollerFlow: IntegrationFlow + + companion object { + lateinit var listAppender: ListAppender + + @JvmStatic + @BeforeAll + fun setupLogger() { + val loggerContext = LogManager.getContext(false) as LoggerContext + listAppender = ListAppender("TestAppender") + listAppender.start() + loggerContext.configuration.addAppender(listAppender) + loggerContext.rootLogger.addAppender(listAppender) + loggerContext.updateLoggers() + } + + @JvmStatic + @AfterAll + fun cleanupLogger() { + val loggerContext = LogManager.getContext(false) as LoggerContext + loggerContext.rootLogger.removeAppender(listAppender) + listAppender.stop() + } + } + + @Test + fun testPollerFlowBeanExists() { + assertThat(pollerFlow).isNotNull + } + + @Test + fun testPollerFlowConfiguration() { + val integrationComponents = pollerFlow.integrationComponents + assertThat(integrationComponents).isNotNull + assertThat(integrationComponents.size).isGreaterThan(0) + } + + @Test + fun testPollerIsActiveAndRunning() { + await() + .atMost(Duration.ofSeconds(5)) + .until { listAppender.events.isNotEmpty() } + + assertThat(listAppender.events) + .anyMatch { event -> + event.toString() + .contains("org.springframework.integration.samples.helloworld Level=INFO " + + "Message=GenericMessage [payload=")} + + } +} diff --git a/build.gradle b/build.gradle index b48103284..16b23a149 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,7 @@ buildscript { + ext { + kotlinVersion = '2.2.21' + } repositories { mavenCentral() gradlePluginPortal() @@ -9,6 +12,8 @@ buildscript { classpath 'io.spring.gradle:dependency-management-plugin:1.1.7' classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion" classpath 'org.gretty:gretty:4.1.10' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion" } } @@ -177,6 +182,55 @@ subprojects { subproject -> } } + if (subproject.plugins.hasPlugin('kotlin')) { + def plugins = asNode().build?.find()?.plugins?.find() + if (!plugins) { + plugins = asNode().appendNode('build').with { + appendNode('sourceDirectory', '${project.basedir}/src/main/kotlin') + appendNode('testSourceDirectory', '${project.basedir}/src/test/kotlin') + appendNode('plugins') + } + } + + plugins.appendNode('plugin') + .with { + appendNode('groupId', 'org.jetbrains.kotlin') + appendNode('artifactId', 'kotlin-maven-plugin') + appendNode('version', property('kotlinVersion')) + appendNode('configuration').with { + appendNode('args').with { + appendNode('arg', '-Xjsr305=strict') + } + appendNode('compilerPlugins').with { + appendNode('plugin', 'spring') + } + } + appendNode('executions').with { + appendNode('execution').with { + appendNode('id', 'compile') + appendNode('phase', 'compile') + appendNode('goals').with { + appendNode('goal', 'compile') + } + } + appendNode('execution').with { + appendNode('id', 'test-compile') + appendNode('phase', 'test-compile') + appendNode('goals').with { + appendNode('goal', 'test-compile') + } + } + } + appendNode('dependencies').with { + appendNode('dependency').with { + appendNode('groupId', 'org.jetbrains.kotlin') + appendNode('artifactId', 'kotlin-maven-allopen') + appendNode('version', property('kotlinVersion')) + } + } + } + } + def pomDeps = asNode().dependencies.find() if (!pomDeps) { pomDeps = asNode().appendNode('dependencies') @@ -212,6 +266,13 @@ subprojects { subproject -> targetCompatibility = JavaVersion.VERSION_17 } + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = '17' + } + } + + compileTestJava { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 @@ -221,6 +282,8 @@ subprojects { subproject -> ext { artemisVersion = '2.41.0' aspectjVersion = '1.9.24' + assertjVersion = '3.27.6' + awaitilityVersion = '4.2.2' commonsDigesterVersion = '2.1' commonsDbcpVersion = '2.13.0' commonsFileUploadVersion = '1.6.0' @@ -609,6 +672,35 @@ project('helloworld-groovy') { api "org.apache.logging.log4j:log4j-core:$log4jVersion" api "org.springframework.integration:spring-integration-groovy" testImplementation "org.apache.logging.log4j:log4j-core-test:$log4jVersion" + testImplementation "org.awaitility:awaitility:$awaitilityVersion" + } + + tasks.register ('runHelloWorldApp', JavaExec) { + mainClass = 'org.springframework.integration.samples.helloworld.HelloWorldApp' + classpath = sourceSets.main.runtimeClasspath + } + + tasks.register ('runPollerApp', JavaExec) { + mainClass = 'org.springframework.integration.samples.helloworld.PollerApp' + classpath = sourceSets.main.runtimeClasspath + } + +} + +project('helloworld-kotlin') { + description = 'Hello World Sample for Kotlin Developers' + + apply plugin: 'kotlin' + apply plugin: 'kotlin-spring' + + dependencies { + api "org.apache.logging.log4j:log4j-core:$log4jVersion" + api "org.springframework.integration:spring-integration-core" + api "org.jetbrains.kotlin:kotlin-stdlib" + api "org.jetbrains.kotlin:kotlin-reflect" + testImplementation "org.apache.logging.log4j:log4j-core-test:$log4jVersion" + testImplementation "org.awaitility:awaitility:$awaitilityVersion" + testImplementation("org.assertj:assertj-core:$assertjVersion") } tasks.register ('runHelloWorldApp', JavaExec) {