Suppose I have an interface Yoyo
and different realizations of this interface:
interface Yoyo {
fun haha() {
println("hello world")
}
}
@Component class Yoyo1 : Yoyo
@Component class Yoyo2 : Yoyo
@Component class Yoyo3 : Yoyo
@Component class YoyoN : Yoyo
Now I would like to instantiate all beans and do some logic after the context has been initialized:
@SpringBootApplication
class YoyoApp
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(YoyoApp::class.java)
.initializers(beans {
bean {
CommandLineRunner {
val y1 = ref<Yoyo1>()
val y2 = ref<Yoyo2>()
val y3 = ref<Yoyo3>()
val yN = ref<YoyoN>()
arrayOf(y1, y2, y3, yN).forEach { it.haha() }
}
}
})
.run(*args)
}
Instead of manually getting ref to all beans (which is rather tedious), I would like to do this:
val list = ref<List<Yoyo>>()
list.forEach { it.haha() }
However I get an exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.List<?>' available
I know I could do this instead, but I would like use the new Kotlin DSL instead:
@Component
class Hoho : CommandLineRunner {
@Autowired
lateinit var list: List<Yoyo>
override fun run(vararg args: String?) {
list.forEach { it.haha() }
}
}
Is it possible? Any ideas?
P.S. Here is the gist.
The context
mentioned in the previous answer by @zsmb13 was left internal
in favor of the provider<Any>()
function (starting with Spring 5.1.1). So in the end I ended up with the following:
interface Yoyo {
fun haha() {
println("hello world from: ${this.javaClass.canonicalName}")
}
}
@Component class Yoyo1 : Yoyo
@Component class Yoyo2 : Yoyo
@Component class Yoyo3 : Yoyo
@Component class YoyoN : Yoyo
@SpringBootApplication
class YoyoApp
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(YoyoApp::class.java)
.initializers(beans {
bean {
CommandLineRunner {
val list = provider<Yoyo>().toList()
list.forEach { it.haha() }
}
}
})
.run(*args)
}