Home » Kotlin spring dependency injection

Kotlin spring dependency injection

Kotlin Spring dependency injection

1. Overview

This article focuses on Kotlin Spring dependency injection. Dependency injection facilitates decoupling among the classes of your application and provides cleaner code. Your code also becomes easier to test.

2. What is dependency injection in Spring?

Bean: An object that is instantiated, assembled, and managed by the Spring container. Otherwise, a bean is a class instance controlled by the Spring framework. See our bean instantiation article to understand more about bean instantiation.

Dependency: A class object requires objects of other classes to perform its responsibilities. We call them dependencies.

For instance, the below Car class has a primary constructor with the variable owner which is an instance of the Owner class. So you can say Car depends on the Owner class. We refer to this as a dependency. Therefore, when the Spring container instantiates the Car class, it injects its owner dependency.

class Car(private val owner: Owner) {
}

class Owner(private val name: String, private val address: String) {}

Dependency injection (DI): A process whereby the Spring container gives the bean its instance variables. Therefore, DI helps to achieve Inversion of Control (IOC). Here, The Spring container takes the responsibility of object creation and injecting its dependencies instead of the class creating the dependency objects by itself.

2.1. Types of Dependency injection in Spring

We can do dependency injection in one of the below ways

  • Constructor based dependency injection
  • Setter based dependency injection (or)
  • Field based dependency injection

This article focuses on the above Kotlin Spring dependency injection.

3. Kotlin spring constructor injection

First, let’s see about the Kotlin spring constructor injection and then the static factory method injection. The spring container treats both injections similarly.

3.1. Injection using constructor arguments

We provide the dependencies required by the class as arguments to the constructor. So each argument represents a dependency.

@Component
class Car @Autowired constructor (private val owner: Owner) {
    fun getOwner() : Owner {
        return owner
    }
}

class Owner(private val name: String, private val address: String) {}

Note that we have annotated the constructor using @Autowired. This annotation instructs the Spring framework to inject the owner dependency into the Car bean. However, as of Spring 4.3, you no longer need to add @Autowired annotation to the class that has only one constructor.

Since our Car class has only one constructor, you can remove the @Autowired annotation:

@Component
class Car (private val owner: Owner) {
    fun getOwner() : Owner {
        return owner
    }
}

class Owner(private val name: String, private val address: String) {}

Suppose you have a class with more than one constructor, then you should explicitly specify the @Autowired annotation to one constructor that should be used by Spring to inject dependencies.

For example, the below Car class has two constructors. So you had to add @Autowired annotation to the constructor which you want the Spring container to use for injecting dependencies.

class Owner(val name: String, val address: String) {}

class Car @Autowired constructor(val owner: Owner) {
    private var carName : String? = null
    constructor(carName: String, owner: Owner): this(owner) {
        this.carName = carName
    }
   
}

3.2. Injection using static factory method

Suppose you want your class method to decide which object (bean) to instantiate, then you would use the static factory method. A Factory Method is a static method inside the class for creating an object. Therefore, the Spring container creates the object by calling this static factory method.

For example, the below Car class has a static function createInstance that takes the Owner as an argument. Similar to constructor injection, the Spring container injects the owner dependency while calling this static factory method.

class Car private constructor(val owner: Owner) {
   
   companion object {
       fun createInstance(owner: Owner) : Car{
           return Car(owner)
       }
   }
}

3.3. Spring constructor-arg multiple arguments injection

Constructor argument resolution matching occurs by using the argument’s type. We are using the XML configuration in this article for bean definition.

package com.tedblob

class Car(owner: Owner, dealer: Dealer)

For example, the above Owner and Dealer classes do not have any inheritance relationship, meaning they are not subclasses of any common superclass, so there is no ambiguity.

Therefore, the following bean configuration works fine, and you do not need to specify the constructor argument indexes or types explicitly in the <constructor-arg/> element. The <constructor-arg/> helps you to define the arguments of your constructor in the XML bean definition.

<beans>
    <bean id="car" class="com.tedblob.Car">
        <constructor-arg ref="owner"/>
        <constructor-arg ref="dealer"/>
    </bean>

    <bean id="owner" class="com.tedblob.Owner"/>

    <bean id="dealer" class="com.tedblob.Dealer"/>
</beans>

3.3.1. Spring constructor injection – argument type matching

Suppose you have a PurchaseStatus class with boolean and string primitive variables.

package com.tedblob

class PurchaseStatus(val isPurchased: Boolean, val nameOfBuyer: String) {
}

If you try to specify the below bean definition, it won’t work. Because Spring cannot determine the type of the value, meaning it cannot determine whether the value=”true” belongs to String or Boolean.

<bean id="purchaseStatus" class="com.tedblob.PurchaseStatus">
    <constructor-arg value="true"/>
    <constructor-arg value="JB"/>
</bean>

Therefore, you should explicitly specify the type of the constructor argument by using the type attribute as below:

<bean id="purchaseStatus" class="com.tedblob.PurchaseStatus">
    <constructor-arg type="Boolean" value="true"/>
    <constructor-arg type="java.lang.String" value="JB"/>
</bean>

Here, the Spring knows that the value=”true” belongs to Boolean type and so resolves the constructor arguments accordingly.

3.3.2. Constructor injection – argument index

You can also use the index attribute alternatively to specify the index of constructor arguments:

<bean id="purchaseStatus" class="com.tedblob.PurchaseStatus">
    <constructor-arg index="0" value="true"/>
    <constructor-arg index="1" value="JB"/>
</bean>

In the above code, index 0 refers to the boolean first argument of the constructor, index 1 refers to the string second argument of the constructor. Besides resolving the ambiguity of multiple simple values, specifying an index resolves ambiguity where a constructor has two arguments of the same type.

Consider the below class Bug that contains two string type desc and latestComment arguments in the constructor.

class Bug(val desc: String, val latestComment: String)

You can resolve the ambiguity of the same type by using the index as below:

<bean id="bug" class="com.tedblob.Bug">
    <constructor-arg index="0" value="Bug on UI home page"/>
    <constructor-arg index="1" value="In review by JB"/>
</bean>

3.3.3. Constructor injection – argument name

You can also use the constructor parameter name for value disambiguation using the name tag:

<bean id="bug" class="com.tedblob.Bug">
    <constructor-arg name="desc" value="Bug on UI home page"/>
    <constructor-arg name="latestComment" value="In review by JB"/>
</bean>

Note that this will work only if you enable debug flag in your app. Alternatively, you can use the @ConstructorProperties JDK annotation to name your constructor arguments as below:

package com.tedblob

class Bug
@ConstructorProperties("desc", "latestComment")
constructor(val desc: String, val latestComment: String)

4. Kotlin setter based dependency injection

You can provide the required dependencies as method arguments to your class rather than using the constructor or static factory method arguments.

Annotate your setter method with the @Autorwired annotation.

Spring container will look at the @Autowired annotation and calls your setter method to inject the required dependencies.

First, let’s look at the below example. The updateBug setter method has the @Autowired annotation and the Spring container invokes this setter method and injects the desc and latestComment dependencies.

Note that the variables have the lateinit specifier to show that the Spring container will assign the variable at a later point in time.

class Bug {
   lateinit var desc: String;
   lateinit var latestComment: String;
   
    // a setter method so that the Spring container can inject desc and latestComment dependencies
   @Autowired
   fun updateBug(desc: String, latestComment: String) {
       this.desc = desc;
       this.latestComment = latestComment;
   }
}

5. Kotlin field based dependency injection

You can assign the required dependencies directly to the fields by annotating them with @Autowired annotation.

Let’s take a similar example in Kotlin. We have @Autowired annotation to the field variables desc and latestComment. The Spring container looks for the @Autowired annotation in the field variables and injects the dependencies.

class Bug {
   @Autowired
   lateinit var desc: String
   @Autowired
   lateinit var latestComment: String
}

6. Conclusion

In this article, we have discussed the Kotlin Spring dependency injection with examples.

1 thought on “Kotlin spring dependency injection”

  1. Pingback: Kotlin spring commandlinerunner - TedBlob

Leave a Reply

Your email address will not be published. Required fields are marked *