4

I don't get Spring-based setter dependency injection in Kotlin to work as it always terminates with the error message "lateinit property api has not been initialized". I could reduce the problem to the following scenario: There is an interface

interface IApi {
  fun retrieveContent(): String
}

which is implemented by

class Api : IApi {
    override fun retrieveContent() = "Some Content"
}

I want to use the implementation in another class where the dependency injection is supposed to take place:

@Component
class SomeController {
    @Autowired lateinit var api: IApi
    fun printReceivedContent() {
        print(api.retrieveContent())
    }
}

However, the application terminates with the above-mentioned error message. My Spring config looks as follows:

@Configuration
open class DIConfig {
    @Bean
    open fun getApiInstance(): IApi = Api()
}

In the main function I load the application context and call the method:

fun main(args: Array<String>) {
    val context = AnnotationConfigApplicationContext()
    context.register(DIConfig::class.java)
    context.refresh()

    val controller = SomeController()
    controller.printReceivedContent()
}

What is the problem here?

Patrick
  • 184
  • 1
  • 1
  • 12

3 Answers3

3

Spring isn't involved if you just call the constructor yourself like that. Same as in Java,

val controller = context.getBean(SomeController::class.java)

Spring Framework 5.0 adds Kotlin extensions, so you could also write either one of

val controller = context.getBean<SomeController>()
val controller: SomeController = context.getBean()
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • Thanks! The way you described it works. In the configuration file, however, I need to add the following bean definition: `@Bean open fun getSomeController() = SomeController()` Is there any way to omit this "unnecessary" code? – Patrick Nov 09 '17 at 21:29
0

your api is currently no a bean managed by spring, try annotating it with @Service or @Component

-1

The @Autowired is usually added to the setter of a property. So instead of using it for the property, you should explicitly annotate the setter:

@set:Autowired lateinit var api: IApi
tynn
  • 38,113
  • 8
  • 108
  • 143
  • Unfortunately, this doesn't work. Explicitly annotating the setter like `lateinit var api: IApi @Autowired set` doesn't work either. – Patrick Nov 09 '17 at 16:30