Skip to content

Kotlin @Qualifier

  • by
Kotlin @Qualifier

1. Overview

In this article, we will learn about the @Qualifier annotation in Kotlin Spring.

1.1. Spring Kotlin dependency injection

Dependency injection (DI) is a process whereby the Spring container gives the bean its instance variables. Here, The Spring container takes the responsibility of object creation and injecting its dependencies rather than the class creating the dependency objects by itself.

Let’s first see an example to understand dependency injection.

Consider the following Drive class that depends on car instance. We mention the car dependency required by the class as an argument to the constructor.

@Component
class Drive(@Autowired val car: Car)
class Car(name: String, number: String)

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

Since we have only one argument, there is no ambiguity and the Spring framework resolves with no issues.

2. Purpose of Kotlin Spring @Qualifier

Ambiguity happens when multiple beans implement the same type and therefore Spring fails to resolve the dependency.

Consider the following interface Vehicle.

interface Vehicle
{
   fun getNumber(): String
}

Both the Car and Bike classes implement the same Vehicle interface.

/* Car class */
@Service
class Car : Vehicle
{
    override fun getNumber() : String {
        return "CAR"
    }
}
/* Bike class */
@Service
class Bike : Vehicle
{
    override fun getNumber(): String {
        return "BIKE"
    }
}

The Drive class requires vehicle implementation injected by the Spring framework. However, since there are two implementations exists for the Vehicle interface, ambiguity arises and Spring cannot resolve.

@Component
class Drive @Autowired constructor(private val vehicle: Vehicle) {
    fun print() {
        println(vehicle.getNumber())
    }
}

If you execute the code, then the error “Drive required a single bean, but 2 were found” happens at compile time.

Parameter 0 of constructor in com.tedblob.dependencyinjection.component.Drive required a single bean, but 2 were found:
	- bike: defined in file [D:\Gayathri\Business\Blog\Spring\dependencyinjection\dependencyinjection\target\classes\com\tedblob\dependencyinjection\services\Bike.class]
	- car: defined in file [D:\Gayathri\Business\Blog\Spring\dependencyinjection\dependencyinjection\target\classes\com\tedblob\dependencyinjection\services\Car.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

Now let’s use the @Qualifier annotation to fix this issue.

2.2. Use @Qualifier annotation in Kotlin

@Primary?is an effective way to use autowiring by type with several instances when you can determine one primary candidate. Alternatively, you can use Spring’s?@Qualifier?annotation to control the selection process using the bean name. See this article to know the differences between the @Qualifier and @Primary annotations.

You can provide a name for each bean implementation using?@Qualifier?annotation. This helps to eliminate the ambiguity.

The following Drive needs only the Bike implementation of the Vehicle type. So you can use the @Qualifier("bike") to let Spring resolve the Bike dependency.

@Component
class Drive(@Qualifier("bike") private val vehicle: Vehicle) {
    fun print() {
        println(vehicle.getNumber())
    }
}

3. Conclusion

To sum up, we have learned the @Qualifier annotation in Spring Kotlin.

Leave a Reply

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