How to use spring annotations like @Autowired in kotlin?

SpringKotlin

Spring Problem Overview


Is it possible to do something like following in Kotlin?

@Autowired
internal var mongoTemplate: MongoTemplate

@Autowired
internal var solrClient: SolrClient

Spring Solutions


Solution 1 - Spring

Recommended approach to do Dependency Injection in Spring is constructor injection:

@Component
class YourBean(
    private val mongoTemplate: MongoTemplate, 
    private val solrClient: SolrClient
) {
  // code
}

Prior to Spring 4.3 constructor should be explicitly annotated with Autowired:

@Component
class YourBean @Autowired constructor(
    private val mongoTemplate: MongoTemplate, 
    private val solrClient: SolrClient
) {
  // code
}

In rare cases, you might like to use field injection, and you can do it with the help of lateinit:

@Component
class YourBean {

	@Autowired
	private lateinit var mongoTemplate: MongoTemplate

	@Autowired
	private lateinit var solrClient: SolrClient
}

Constructor injection checks all dependencies at bean creation time and all injected fields is val, at other hand lateinit injected fields can be only var, and have little runtime overhead. And to test class with constructor, you don't need reflection.

Links:

  1. Documentation on lateinit
  2. Documentation on constructors
  3. Developing Spring Boot applications with Kotlin

Solution 2 - Spring

Yes, java annotations are supported in Kotlin mostly as in Java. One gotcha is annotations on the primary constructor requires the explicit 'constructor' keyword:

From https://kotlinlang.org/docs/reference/annotations.html > If you need to annotate the primary constructor of a class, you need to add the constructor keyword to the constructor declaration, and add the annotations before it:

class Foo @Inject constructor(dependency: MyDependency) {
  // ...
}

Solution 3 - Spring

You can also autowire dependencies through the constructor. Remember to annotate your dependencies with @Configuration, @Component, @Service etc

import org.springframework.stereotype.Component

@Component
class Foo (private val dependency: MyDependency) {
    //...
}

  

Solution 4 - Spring

like that

@Component class Girl( @Autowired var outfit: Outfit)

Solution 5 - Spring

If you want property injection but don't like lateinit var, here is my solution using property delegate:

private lateinit var ctx: ApplicationContext

@Component
private class CtxVarConfigurer : ApplicationContextAware {
    override fun setApplicationContext(context: ApplicationContext) {
        ctx = context
    }
}

inline fun <reified T : Any> autowired(name: String? = null) = Autowired(T::class.java, name)

class Autowired<T : Any>(private val javaType: Class<T>, private val name: String?) {

    private val value by lazy {
        if (name == null) {
            ctx.getBean(javaType)
        } else {
            ctx.getBean(name, javaType)
        }
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value

}

Then you can use the much better by delegate syntax:

@Service
class MyService {

    private val serviceToBeInjected: ServiceA by autowired()

    private val ambiguousBean: AmbiguousService by autowired("qualifier")

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioneendroroyView Question on Stackoverflow
Solution 1 - SpringRuslanView Answer on Stackoverflow
Solution 2 - SpringMike BuhotView Answer on Stackoverflow
Solution 3 - SpringMr.TurtleView Answer on Stackoverflow
Solution 4 - SpringNankaiView Answer on Stackoverflow
Solution 5 - SpringYihao GaoView Answer on Stackoverflow