From ff675f52269ef60c694f647ccaddefb58c174097 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Mon, 26 Dec 2016 14:09:30 +0100 Subject: [PATCH] Add Kotlin extensions for bean registration and retrieval Issue: SPR-15048 --- build.gradle | 15 +++-- .../beans/factory/BeanFactoryExtension.kt | 29 ++++++++++ .../factory/ListableBeanFactoryExtension.kt | 56 +++++++++++++++++++ .../GenericApplicationContextExtension.kt | 47 ++++++++++++++++ ...GenericApplicationContextExtensionTests.kt | 45 +++++++++++++++ 5 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanFactoryExtension.kt create mode 100644 spring-beans/src/main/kotlin/org/springframework/beans/factory/ListableBeanFactoryExtension.kt create mode 100644 spring-context/src/main/kotlin/org/springframework/context/support/GenericApplicationContextExtension.kt create mode 100644 spring-context/src/test/kotlin/org/springframework/context/support/GenericApplicationContextExtensionTests.kt diff --git a/build.gradle b/build.gradle index e738f813c0e..56c66b2f4c4 100644 --- a/build.gradle +++ b/build.gradle @@ -326,7 +326,7 @@ project("spring-build-src") { project("spring-core") { description = "Spring Core" - // Kotlin compiler does not support JDK 9 yet + // Kotlin compiler does not support JDK 9 yet, see https://youtrack.jetbrains.com/issue/KT-14988 if (!JavaVersion.current().java9Compatible) { apply plugin: "kotlin" } @@ -430,7 +430,7 @@ project("spring-core") { project("spring-beans") { description = "Spring Beans" - // Kotlin compiler does not support JDK 9 yet + // Kotlin compiler does not support JDK 9 yet, see https://youtrack.jetbrains.com/issue/KT-14988 if (!JavaVersion.current().java9Compatible) { apply plugin: "kotlin" } @@ -514,6 +514,10 @@ project("spring-context") { description = "Spring Context" apply plugin: "groovy" + // Kotlin compiler does not support JDK 9 yet, see https://youtrack.jetbrains.com/issue/KT-14988 + if (!JavaVersion.current().java9Compatible) { + apply plugin: "kotlin" + } dependencies { compile(project(":spring-aop")) @@ -536,6 +540,7 @@ project("spring-context") { optional("org.aspectj:aspectjweaver:${aspectjVersion}") optional("org.codehaus.groovy:groovy-all:${groovyVersion}") optional("org.beanshell:bsh:2.0b4") + optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}") testCompile("org.apache.commons:commons-pool2:2.4.2") testCompile("org.slf4j:slf4j-api:${slf4jVersion}") testCompile("javax.inject:javax.inject-tck:1") @@ -581,7 +586,7 @@ project("spring-oxm") { project("spring-messaging") { description = "Spring Messaging" - // Kotlin compiler does not support JDK 9 yet + // Kotlin compiler does not support JDK 9 yet, see https://youtrack.jetbrains.com/issue/KT-14988 if (!JavaVersion.current().java9Compatible) { apply plugin: "kotlin" } @@ -726,7 +731,7 @@ project("spring-context-indexer") { project("spring-web") { description = "Spring Web" - // Kotlin compiler does not support JDK 9 yet + // Kotlin compiler does not support JDK 9 yet, see https://youtrack.jetbrains.com/issue/KT-14988 if (!JavaVersion.current().java9Compatible) { apply plugin: "kotlin" } @@ -819,7 +824,7 @@ project("spring-web") { project("spring-web-reactive") { description = "Spring Web Reactive" - // Kotlin compiler does not support JDK 9 yet + // Kotlin compiler does not support JDK 9 yet, see https://youtrack.jetbrains.com/issue/KT-14988 if (!JavaVersion.current().java9Compatible) { apply plugin: "kotlin" } diff --git a/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanFactoryExtension.kt b/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanFactoryExtension.kt new file mode 100644 index 00000000000..d9bac3c037f --- /dev/null +++ b/spring-beans/src/main/kotlin/org/springframework/beans/factory/BeanFactoryExtension.kt @@ -0,0 +1,29 @@ +package org.springframework.beans.factory + +import kotlin.reflect.KClass + +/** + * Extension for [BeanFactory] providing [KClass] based API. + * + * @since 5.0 + */ +object BeanFactoryExtension { + + /** + * @see BeanFactory.getBean(Class) + */ + fun BeanFactory.getBean(requiredType: KClass) = getBean(requiredType.java) + + /** + * @see BeanFactory.getBean(String, Class) + */ + fun BeanFactory.getBean(name: String, requiredType: KClass) = + getBean(name, requiredType.java) + + /** + * @see BeanFactory.getBean(Class, Object...) + */ + fun BeanFactory.getBean(requiredType: KClass, vararg args:Any) = + getBean(requiredType.java, *args) + +} diff --git a/spring-beans/src/main/kotlin/org/springframework/beans/factory/ListableBeanFactoryExtension.kt b/spring-beans/src/main/kotlin/org/springframework/beans/factory/ListableBeanFactoryExtension.kt new file mode 100644 index 00000000000..ffe70c84c02 --- /dev/null +++ b/spring-beans/src/main/kotlin/org/springframework/beans/factory/ListableBeanFactoryExtension.kt @@ -0,0 +1,56 @@ +package org.springframework.beans.factory + +import kotlin.reflect.KClass + +/** + * Extension for [ListableBeanFactory] providing [KClass] based API. + * + * @since 5.0 + */ +object ListableBeanFactoryExtension { + + /** + * @see ListableBeanFactory.getBeanNamesForType(Class) + */ + fun ListableBeanFactory.getBeanNamesForType(type: KClass) = + getBeanNamesForType(type.java) + + /** + * @see ListableBeanFactory.getBeanNamesForType(Class, boolean, boolean) + */ + fun ListableBeanFactory.getBeanNamesForType(type: KClass, + includeNonSingletons: Boolean, allowEagerInit: Boolean) = + getBeanNamesForType(type.java, includeNonSingletons, allowEagerInit) + + /** + * @see ListableBeanFactory.getBeansOfType(Class) + */ + fun ListableBeanFactory.getBeansOfType(type: KClass) = + getBeansOfType(type.java) + + /** + * @see ListableBeanFactory.getBeansOfType(Class, boolean, boolean) + */ + fun ListableBeanFactory.getBeansOfType(type: KClass, + includeNonSingletons: Boolean, allowEagerInit: Boolean) = + getBeansOfType(type.java, includeNonSingletons, allowEagerInit) + + /** + * @see ListableBeanFactory.getBeanNamesForAnnotation + */ + fun ListableBeanFactory.getBeanNamesForAnnotation(type: KClass) = + getBeanNamesForAnnotation(type.java) + + /** + * @see ListableBeanFactory.getBeansWithAnnotation + */ + fun ListableBeanFactory.getBeansWithAnnotation(type: KClass) = + getBeansWithAnnotation(type.java) + + /** + * @see ListableBeanFactoryExtension.findAnnotationOnBean + */ + fun ListableBeanFactory.findAnnotationOnBean(beanName:String, type: KClass) = + findAnnotationOnBean(beanName, type.java) + +} diff --git a/spring-context/src/main/kotlin/org/springframework/context/support/GenericApplicationContextExtension.kt b/spring-context/src/main/kotlin/org/springframework/context/support/GenericApplicationContextExtension.kt new file mode 100644 index 00000000000..61ca6241658 --- /dev/null +++ b/spring-context/src/main/kotlin/org/springframework/context/support/GenericApplicationContextExtension.kt @@ -0,0 +1,47 @@ +package org.springframework.context.support + +import org.springframework.beans.factory.config.BeanDefinitionCustomizer +import java.util.function.Supplier +import kotlin.reflect.KClass + +/** + * Extension for [GenericApplicationContext] providing [KClass] based API and + * avoiding specifying a class parameter for the [Supplier] based variant thanks to + * Kotlin reified type parameters. + * + * @since 5.0 + */ +object GenericApplicationContextExtension { + + /** + * @see GenericApplicationContext.registerBean(Class, BeanDefinitionCustomizer...) + */ + fun GenericApplicationContext.registerBean(beanClass: KClass, + vararg customizers: BeanDefinitionCustomizer) { + registerBean(beanClass.java, *customizers) + } + + /** + * @see GenericApplicationContext.registerBean(String, Class, BeanDefinitionCustomizer...) + */ + fun GenericApplicationContext.registerBean(beanName: String, beanClass: KClass, + vararg customizers: BeanDefinitionCustomizer) { + registerBean(beanName, beanClass.java, *customizers) + } + + /** + * @see GenericApplicationContext.registerBean(Class, Supplier, BeanDefinitionCustomizer...) + */ + inline fun GenericApplicationContext.registerBean(supplier: Supplier, + vararg customizers: BeanDefinitionCustomizer) { + registerBean(T::class.java, supplier, *customizers) + } + + /** + * @see GenericApplicationContext.registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) + */ + inline fun GenericApplicationContext.registerBean(name: String, + supplier: Supplier, vararg customizers: BeanDefinitionCustomizer) { + registerBean(name, T::class.java, supplier, *customizers) + } +} diff --git a/spring-context/src/test/kotlin/org/springframework/context/support/GenericApplicationContextExtensionTests.kt b/spring-context/src/test/kotlin/org/springframework/context/support/GenericApplicationContextExtensionTests.kt new file mode 100644 index 00000000000..f707d204fd5 --- /dev/null +++ b/spring-context/src/test/kotlin/org/springframework/context/support/GenericApplicationContextExtensionTests.kt @@ -0,0 +1,45 @@ +package org.springframework.context.support + +import org.junit.Assert.assertNotNull +import org.junit.Test +import org.springframework.context.support.GenericApplicationContextExtension.registerBean +import org.springframework.beans.factory.BeanFactoryExtension.getBean +import java.util.function.Supplier + +class GenericApplicationContextExtensionTests { + + @Test + fun registerBeanWithClass() { + val context = GenericApplicationContext() + context.registerBean(BeanA::class) + context.refresh() + assertNotNull(context.getBean(BeanA::class)) + } + + @Test + fun registerBeanWithNameAndClass() { + val context = GenericApplicationContext() + context.registerBean("a", BeanA::class) + context.refresh() + assertNotNull(context.getBean("a")) + } + + @Test + fun registerBeanWithSupplier() { + val context = GenericApplicationContext() + context.registerBean(Supplier { BeanA() }) + context.refresh() + assertNotNull(context.getBean(BeanA::class)) + } + + @Test + fun registerBeanWithNameAndSupplier() { + val context = GenericApplicationContext() + context.registerBean("a", Supplier { BeanA() }) + context.refresh() + assertNotNull(context.getBean("a")) + } + + internal class BeanA + +}