0

BubbleSort.java This class implements SortAlgorithm interface

package com.prakash.Spring.Example;

import org.springframework.stereotype.Component;

@Component
@Qualifier("bubbleSort")
public class BubbleSort implements SortAlgorithm {

    public void sort() {
        System.out.println("Sort from Bubble Sort");
    }
}

QuickSort.java This class implements SortAlgorithm interface package com.prakash.Spring.Example;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.context.annotation.Primary;

import org.springframework.stereotype.Component;

@Component
@Qualifier("quickSort")
public class QuickSort implements SortAlgorithm {

    @Override
    public void sort() {
        System.out.println("Sort from Quick Sort");
    }

}

SortAlgorithm.java

package com.prakash.Spring.Example;

public interface SortAlgorithm {
 void sort();
}

BinarySearch.java In this class, I would like to use quickSort bean as my component.

package com.prakash.Spring.Example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class BinarySearch {

    @Autowired
    @Qualifier("quickSort")
    private SortAlgorithm sortAlgorithm;

    public BinarySearch(SortAlgorithm sortAlgorithm) {
        super();
        this.sortAlgorithm = sortAlgorithm;
    }

    public int[] search(int[] numbers) {
        sortAlgorithm.sort();
        System.out.println("This is from BinarySearch");
        return numbers;
    }
}

ComplexBusinessService.java In this class, I'm getting the bean using getBean method

package com.prakash.Spring.Example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class ComplexBussinessService {

    public static void main(String[] args) {

        ConfigurableApplicationContext applicationContext = SpringApplication.run(ComplexBussinessService.class, args);
        BinarySearch binarySearch = applicationContext.getBean(BinarySearch.class);
        int[] result = binarySearch.search(new int[] { 2, 4, 3 });
        for (int i : result) {
            System.out.print(i+" ");
        }
        applicationContext.close();

    }
}

4 Answers4

5

Here is why. Actually, this is tricky part of Spring, understanding when and how dependency injection occurs.

Here is the order of dependency injection:

  1. Injecting with the constructor of the class
  2. Injecting fields (annotated by @Autowired)
  3. Injecting the setters (also annotated with @Autowired)

The tricks is here:
If a class annotated by @Component has also only one non-default constructor, then this constructor is automatically called. As you call first the constructor, and then the field, your @Qualifier is not even interpreted by Spring because it fails during the constructor call, hence the exception.

To solve this, you have two options:

  1. Either, remove your constructor from BinarySearch. Spring will then call the default constructor new BinarySearch() and then performing the injection in your field sortAlgorithm using the @Qualifier.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class BinarySearch {

    @Autowired
    @Qualifier("quickSort")
    private SortAlgorithm sortAlgorithm;

    public int[] search(int[] numbers) {
        sortAlgorithm.sort();
        System.out.println("This is from BinarySearch");
        return numbers;
    }
}
  1. Or remove the annotation of your field and add a @Qualifier in your constructor parameter:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class BinarySearch {

    private SortAlgorithm sortAlgorithm;

    public BinarySearch(@Qualifier("quickSort") SortAlgorithm sortAlgorithm) {
        super();
        this.sortAlgorithm = sortAlgorithm;
    }

    public int[] search(int[] numbers) {
        sortAlgorithm.sort();
        System.out.println("This is from BinarySearch");
        return numbers;
    }
}

Hope it helps !

RUARO Thibault
  • 2,672
  • 1
  • 9
  • 14
0

you also have to set your @Qualifier annotation on the type you annotated with @Component, e.g. like this:

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.context.annotation.Primary;

import org.springframework.stereotype.Component;

@Component
@Qualifier("quickSort")
public class QuickSort implements SortAlgorithm {

    @Override
    public void sort() {
        System.out.println("Sort from Quick Sort");
    }

}
0
package com.prakash.Spring.Example;

import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Qualifier;
@Component
@Qualifier("bubbleSort")
public class BubbleSort implements SortAlgorithm {

public void sort() {
    System.out.println("Sort from Bubble Sort");
}
}

I can't see import statement for Qualifier annotation in BubbleSort class. Could you import and then try if it works

Gaurav Dhiman
  • 953
  • 6
  • 11
0

Adding to the excellent answer from "RUARO Thibault", another way to resolve this error is how Spring Boot mentions when the application fails to start up.

Annotating one of the implementation class with @Primary will make that bean as the primary candidate when multiple candidates are found for autowiring.

@Component
@Qualifier("b")
@Primary
public class BubbleSortAlgorithm implements SortAlgorithm {}

In this case , BinarySearch bean will be constructed with the candidate marked @Primary . Then the field injection happens are replaces it with the bean with @Qualifier("quickSort")

R.G
  • 6,436
  • 3
  • 19
  • 28