Browse Source

Add 'fromApplication' and 'with' Kotlin extension functions

Update `SpringApplicationExtensions.kt` with `fromApplication` and
`with` functions that make `SpringApplication.from(...)` easier to use
with Kotlin.

Fixes gh-35756
pull/35733/head
Phillip Webb 3 years ago
parent
commit
1669b81af7
  1. 10
      spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/testing/testcontainers/atdevelopmenttime/launch/TestMyApplication.kt
  2. 13
      spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/testing/testcontainers/atdevelopmenttime/test/TestMyApplication.kt
  3. 36
      spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
  4. 14
      spring-boot-project/spring-boot/src/test/kotlin/org/springframework/boot/SpringApplicationExtensionsTests.kt
  5. 11
      spring-boot-project/spring-boot/src/test/kotlin/org/springframework/boot/kotlinsample/TestKotlinApplication.kt

10
spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/testing/testcontainers/atdevelopmenttime/launch/TestMyApplication.kt

@ -16,12 +16,8 @@ @@ -16,12 +16,8 @@
package org.springframework.boot.docs.features.testing.testcontainers.atdevelopmenttime.launch
import org.springframework.boot.SpringApplication
import org.springframework.boot.docs.features.testing.testcontainers.atdevelopmenttime.launch.main as myApplicationMain
import org.springframework.boot.fromApplication
object Main {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.from(::myApplicationMain).run(*args)
}
fun main(args: Array<String>) {
fromApplication<MyApplication>().run(*args)
}

13
spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/testing/testcontainers/atdevelopmenttime/test/TestMyApplication.kt

@ -16,12 +16,9 @@ @@ -16,12 +16,9 @@
package org.springframework.boot.docs.features.testing.testcontainers.atdevelopmenttime.test
import org.springframework.boot.SpringApplication
import org.springframework.boot.docs.features.testing.testcontainers.atdevelopmenttime.test.main as myApplicationMain
import org.springframework.boot.fromApplication
import org.springframework.boot.with
object Main {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.from(::myApplicationMain).with(MyContainersConfiguration::class.java).run(*args)
}
}
fun main(args: Array<String>) {
fromApplication<MyApplication>().with(MyContainersConfiguration::class).run(*args)
}

36
spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt

@ -17,6 +17,11 @@ @@ -17,6 +17,11 @@
package org.springframework.boot
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.util.Assert
import org.springframework.util.ClassUtils
import org.springframework.util.ReflectionUtils
import kotlin.reflect.KClass
import kotlin.reflect.KType
/**
* Top-level function acting as a Kotlin shortcut allowing to write
@ -40,3 +45,34 @@ inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableAp @@ -40,3 +45,34 @@ inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableAp
*/
inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext =
SpringApplication(T::class.java).apply(init).run(*args)
/**
* Top-level function acting as a Kotlin shortcut allowing to write
* `fromApplication<MyApplication>().with(...)`. This method assumes that
* the `main` function is declared in the same file as `T`.
*
* @author Phillip Webb
* @since 3.1.1
*/
inline fun <reified T : Any> fromApplication(): SpringApplication.Augmented {
val type = T::class
val ktClassName = type.qualifiedName + "Kt"
try {
val ktClass = ClassUtils.resolveClassName(ktClassName, type.java.classLoader)
val mainMethod = ReflectionUtils.findMethod(ktClass, "main", Array<String>::class.java)
Assert.notNull(mainMethod, "Unable to find main method")
return SpringApplication.from { ReflectionUtils.invokeMethod(mainMethod!!, null, it) }
} catch (ex: Exception) {
throw IllegalStateException("Unable to use 'fromApplication' with " + type.qualifiedName)
}
}
/**
* Extension function that allows `SpringApplication.Augmented.with` to work with Kotlin classes.
*
* @author Phillip Webb
* @since 3.1.1
*/
fun SpringApplication.Augmented.with(type: KClass<*>): SpringApplication.Augmented {
return this.with(type.java)!!
}

14
spring-boot-project/spring-boot/src/test/kotlin/org/springframework/boot/SpringApplicationExtensionsTests.kt

@ -16,9 +16,11 @@ @@ -16,9 +16,11 @@
package org.springframework.boot
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatIllegalStateException
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.getBean
import org.springframework.boot.kotlinsample.TestKotlinApplication
import org.springframework.boot.web.servlet.server.MockServletWebServerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@ -67,6 +69,18 @@ class SpringApplicationExtensionsTests { @@ -67,6 +69,18 @@ class SpringApplicationExtensionsTests {
assertThat(environment).isEqualTo(context.environment)
}
@Test
fun `Kotlin fromApplication() top level function`() {
val context = fromApplication<TestKotlinApplication>().with(ExampleWebConfig::class).run().applicationContext
assertThat(context.getBean<MockServletWebServerFactory>()).isNotNull
}
@Test
fun `Kotlin fromApplication() top level function when no main`() {
assertThatIllegalStateException().isThrownBy { fromApplication<ExampleWebConfig>().run() }
.withMessage("Unable to use 'fromApplication' with org.springframework.boot.SpringApplicationExtensionsTests.ExampleWebConfig")
}
@Configuration(proxyBeanMethods = false)
internal open class ExampleWebConfig {

11
spring-boot-project/spring-boot/src/test/kotlin/org/springframework/boot/kotlinsample/TestKotlinApplication.kt

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
package org.springframework.boot.kotlinsample
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Configuration
@Configuration(proxyBeanMethods = false)
open class TestKotlinApplication
fun main(args: Array<String>) {
runApplication<TestKotlinApplication>(*args)
}
Loading…
Cancel
Save