17

At https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/kotlin/org/springframework/context/support/BeanDefinitionDsl.kt the comment shows how to define Spring Beans via the new "Functional bean definition Kotlin DSL". I also found https://github.com/sdeleuze/spring-kotlin-functional. However, this example uses just plain Spring and not Spring Boot. Any hint how to use the DSL together with Spring Boot is appreciated.

Juergen Zimmermann
  • 2,084
  • 7
  • 29
  • 43
  • Have you just tried it out, e.g. by putting this bean definition into a controller (which is discovered by spring boot)? – guenhter Aug 30 '17 at 05:52
  • 1
    Yes, I tried a `@Configuration` class with an `@Bean` method returning the result of `beans {...}`. Then I got the exception `"... No qualifying bean of type '...' available ..."` when I remove `@Service` and declare the service class inside the `beans {...}` lambda above. – Juergen Zimmermann Aug 30 '17 at 09:11

3 Answers3

27

Spring Boot is based on Java Config, but should allow experimental support of user-defined functional bean declaration DSL via ApplicationContextInitializer support as described here.

In practice, you should be able to declare your beans for example in a Beans.kt file containing a beans() function.

fun beans() = beans {
    // Define your bean with Kotlin DSL here
}

Then in order to make it taken in account by Boot when running main() and tests, create an ApplicationContextInitializer class as following:

class BeansInitializer : ApplicationContextInitializer<GenericApplicationContext> {

    override fun initialize(context: GenericApplicationContext) =
        beans().initialize(context)

}

And ultimately, declare this initializer in your application.properties file:

context.initializer.classes=com.example.BeansInitializer  

You will find a full example here and can also follow this issue about dedicated Spring Boot support for functional bean registration.

Sébastien Deleuze
  • 5,950
  • 5
  • 37
  • 38
  • Two questions regarding your answer: * This initialisation will be picked up by the test setup with using a `SpringRunner` with JUnit, right? * Is there any other way of having this behaviour without having to create `properties` files, including this initialisation being picked up on tests? Thanks! – Pedro Felix Mar 03 '18 at 20:22
  • Yes and not yet. – Sébastien Deleuze Mar 12 '18 at 08:11
  • 1
    Side note: we are currently exploring full functional bean definition for Boot with Java or Kotlin DSL in https://github.com/spring-projects/spring-fu incubator project. – Sébastien Deleuze Feb 07 '19 at 09:21
  • What if I want to override a bean? I added allow-bean-definition-overriding: true and am trying to declare a test bean via @Bean but it seems to be ignored. I have tried an exact same setup(basically, just copy pasted) on a project withotu bean DSL and it worked. – yuranos Apr 01 '19 at 12:58
  • Declaring the initializer like that will disable all other ones provided by spring boot, won't it? – Rüdiger Schulz Apr 12 '20 at 18:25
  • Is that what your tests seems to indicate? – Sébastien Deleuze Apr 16 '20 at 14:24
6

Another way to do it in Spring Boot would be :

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args) {
        addInitializers(
                beans {
                    // Define your bean with Kotlin DSL here
                }
        )
    }
}
Sébastien Deleuze
  • 5,950
  • 5
  • 37
  • 38
fg78nc
  • 4,774
  • 3
  • 19
  • 32
2

You can define your beans in *Config.kt file and implement initalize method of ApplicationContextInitializer interface.

override fun initialize(applicationContext: GenericApplicationContext) {
    ....
}

Some bean definition here.

bean<XServiceImpl>("xService")

bean("beanName") {
        BeanConstructor(ref("refBeanName"))
}
Ugur Artun
  • 1,744
  • 2
  • 23
  • 41