Add support for Kotlin autowired ctors w/ optional params
This commit adds support for autowired constructor parameters on Kotlin classes with optional parameters. If some constructor parameters are not available, optional parameter default values will be used instead. Both explicit @Autowired annotated constructor and implicit single constructor automatically autowired are supported. Issue: SPR-15847
This commit is contained in:
@@ -23,51 +23,108 @@ import org.springframework.beans.factory.support.RootBeanDefinition
|
||||
import org.springframework.tests.sample.beans.TestBean
|
||||
|
||||
import org.junit.Assert.*
|
||||
import org.springframework.tests.sample.beans.Colour
|
||||
|
||||
/**
|
||||
* Tests for Kotlin support with [Autowired].
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
class KotlinAutowiredTests {
|
||||
|
||||
@Test
|
||||
fun autowiringWithTarget() {
|
||||
var bf = DefaultListableBeanFactory()
|
||||
var bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
fun `Autowiring with target`() {
|
||||
val bf = DefaultListableBeanFactory()
|
||||
val bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
bpp.setBeanFactory(bf)
|
||||
bf.addBeanPostProcessor(bpp)
|
||||
var bd = RootBeanDefinition(KotlinBean::class.java)
|
||||
val bd = RootBeanDefinition(KotlinBean::class.java)
|
||||
bd.scope = RootBeanDefinition.SCOPE_PROTOTYPE
|
||||
bf.registerBeanDefinition("annotatedBean", bd)
|
||||
var tb = TestBean()
|
||||
val tb = TestBean()
|
||||
bf.registerSingleton("testBean", tb)
|
||||
|
||||
var kb = bf.getBean("annotatedBean", KotlinBean::class.java)
|
||||
val kb = bf.getBean("annotatedBean", KotlinBean::class.java)
|
||||
assertSame(tb, kb.injectedFromConstructor)
|
||||
assertSame(tb, kb.injectedFromMethod)
|
||||
assertSame(tb, kb.injectedField)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun autowiringWithoutTarget() {
|
||||
var bf = DefaultListableBeanFactory()
|
||||
var bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
fun `Autowiring without target`() {
|
||||
val bf = DefaultListableBeanFactory()
|
||||
val bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
bpp.setBeanFactory(bf)
|
||||
bf.addBeanPostProcessor(bpp)
|
||||
var bd = RootBeanDefinition(KotlinBean::class.java)
|
||||
val bd = RootBeanDefinition(KotlinBean::class.java)
|
||||
bd.scope = RootBeanDefinition.SCOPE_PROTOTYPE
|
||||
bf.registerBeanDefinition("annotatedBean", bd)
|
||||
|
||||
var kb = bf.getBean("annotatedBean", KotlinBean::class.java)
|
||||
val kb = bf.getBean("annotatedBean", KotlinBean::class.java)
|
||||
assertNull(kb.injectedFromConstructor)
|
||||
assertNull(kb.injectedFromMethod)
|
||||
assertNull(kb.injectedField)
|
||||
}
|
||||
|
||||
@Test // SPR-15847
|
||||
fun `Autowiring by primary constructor with optional parameter`() {
|
||||
val bf = DefaultListableBeanFactory()
|
||||
val bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
bpp.setBeanFactory(bf)
|
||||
bf.addBeanPostProcessor(bpp)
|
||||
val bd = RootBeanDefinition(KotlinBeanWithOptionalParameter::class.java)
|
||||
bd.scope = RootBeanDefinition.SCOPE_PROTOTYPE
|
||||
bf.registerBeanDefinition("bean", bd)
|
||||
val tb = TestBean()
|
||||
bf.registerSingleton("testBean", tb)
|
||||
|
||||
val kb = bf.getBean("bean", KotlinBeanWithOptionalParameter::class.java)
|
||||
assertSame(tb, kb.injectedFromConstructor)
|
||||
assertEquals("foo", kb.optional)
|
||||
assertEquals("bar", kb.initializedField)
|
||||
}
|
||||
|
||||
@Test // SPR-15847
|
||||
fun `Autowiring by annotated primary constructor with optional parameter`() {
|
||||
val bf = DefaultListableBeanFactory()
|
||||
val bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
bpp.setBeanFactory(bf)
|
||||
bf.addBeanPostProcessor(bpp)
|
||||
val bd = RootBeanDefinition(KotlinBeanWithOptionalParameterAndExplicitConstructor::class.java)
|
||||
bd.scope = RootBeanDefinition.SCOPE_PROTOTYPE
|
||||
bf.registerBeanDefinition("bean", bd)
|
||||
val tb = TestBean()
|
||||
bf.registerSingleton("testBean", tb)
|
||||
|
||||
val kb = bf.getBean("bean", KotlinBeanWithOptionalParameterAndExplicitConstructor::class.java)
|
||||
assertSame(tb, kb.injectedFromConstructor)
|
||||
assertEquals("foo", kb.optional)
|
||||
}
|
||||
|
||||
@Test // SPR-15847
|
||||
fun `Autowiring by annotated secondary constructor with optional parameter`() {
|
||||
val bf = DefaultListableBeanFactory()
|
||||
val bpp = AutowiredAnnotationBeanPostProcessor()
|
||||
bpp.setBeanFactory(bf)
|
||||
bf.addBeanPostProcessor(bpp)
|
||||
val bd = RootBeanDefinition(KotlinBeanWithSecondaryConstructor::class.java)
|
||||
bd.scope = RootBeanDefinition.SCOPE_PROTOTYPE
|
||||
bf.registerBeanDefinition("bean", bd)
|
||||
val tb = TestBean()
|
||||
bf.registerSingleton("testBean", tb)
|
||||
val colour = Colour.BLUE
|
||||
bf.registerSingleton("colour", colour)
|
||||
|
||||
val kb = bf.getBean("bean", KotlinBeanWithSecondaryConstructor::class.java)
|
||||
assertSame(tb, kb.injectedFromConstructor)
|
||||
assertEquals("bar", kb.optional)
|
||||
assertSame(colour, kb.injectedFromSecondaryConstructor)
|
||||
}
|
||||
|
||||
|
||||
class KotlinBean(val injectedFromConstructor: TestBean?) {
|
||||
|
||||
|
||||
var injectedFromMethod: TestBean? = null
|
||||
|
||||
@Autowired
|
||||
@@ -79,4 +136,31 @@ class KotlinAutowiredTests {
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinBeanWithOptionalParameter(
|
||||
val injectedFromConstructor: TestBean,
|
||||
val optional: String = "foo"
|
||||
) {
|
||||
var initializedField: String? = null
|
||||
|
||||
init {
|
||||
initializedField = "bar"
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinBeanWithOptionalParameterAndExplicitConstructor @Autowired constructor(
|
||||
val optional: String = "foo",
|
||||
val injectedFromConstructor: TestBean
|
||||
)
|
||||
|
||||
class KotlinBeanWithSecondaryConstructor(
|
||||
val optional: String = "foo",
|
||||
val injectedFromConstructor: TestBean
|
||||
) {
|
||||
@Autowired constructor(injectedFromSecondaryConstructor: Colour, injectedFromConstructor: TestBean, optional: String = "bar") : this(optional, injectedFromConstructor) {
|
||||
this.injectedFromSecondaryConstructor = injectedFromSecondaryConstructor
|
||||
}
|
||||
|
||||
var injectedFromSecondaryConstructor: Colour? = null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user