7

So, I am trying to learn my way with Spring Boot. I tried @Qualifier and @Autowired but it gives me the following error:

Parameter 0 of constructor in io.cptpackage.springboot.bootdemo.BinarySearch required a single bean, but 2 were found:

Even tho I have provided the right @Qualifier it doesn't work until one of the dependencies has a @Primary annotation, also the name reference doesn't work I to use @Primary or @Qualifier and you know that I am having the issue with the @Qualifier thing. The code is simple and as following.

@Component 
public class BinarySearch {

// Sort, Search, Return the result!
@Autowired
@Qualifier("quick")
Sorter sorter;

public BinarySearch(Sorter sorter) {
    super();
    this.sorter = sorter;
}

public int search(int[] numbersToSearchIn, int targetNumber) {
    sorter.sort(numbersToSearchIn);
    return targetNumber;
 } 
}

The first dependency:

@Component
@Qualifier("bubble")
public class BubbleSort implements Sorter {

    @Override
    public int[] sort(int[] targetArray) {
        System.out.println("Bubble sort!");
        return targetArray;
    }

}

The second dependency:

@Component
@Qualifier("quick")
public class QuickSort implements Sorter {

    @Override
    public int[] sort(int[] targetArray) {
        System.out.println("Quick Sort!");
        return targetArray;
    }

}

Also why is autowiring by name isnot working?

CptPackage
  • 143
  • 1
  • 1
  • 13

2 Answers2

9

@Qualifier is an annotation to specify the bean that you need to inject, it works together with @Autowired.

ff you need to specify the name of a component just put a name @Component("myComponent") and after that when you need to inject it use @Qualifier("myComponent")

For your question try this:

Instead of:

@Component
@Qualifier("bubble")
public class BubbleSort implements Sorter {

Use this:

@Component("quick")
public class BubbleSort implements Sorter {

And finally define one way to inject the bean for example:

Option 1: constructor parameter

@Component 
public class BinarySearch {

// Sort, Search, Return the result!
private final Sorter sorter;

public BinarySearch(@Qualifier("quick")Sorter sorter) {
    super();
    this.sorter = sorter;
}

Option 2 as a class member

@Component 
public class BinarySearch {

// Sort, Search, Return the result!
@Autowired
@Qualifier("quick")
Sorter sorter;

public BinarySearch() {
    super();

}
Daniel C.
  • 5,418
  • 3
  • 23
  • 26
  • I did that already before but still if I don't put the @Primary annotation in any of the two dependencies Quick or Bubble I get the following error. Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'binarySearch' defined in file : Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'io.cptpackage.springboot.bootdemo.Sorter' available: expected single matching bean but found 2: bubble,quick – CptPackage Aug 28 '17 at 01:31
  • yes it is because the `quick` component is injected using constructor and as a member class. Just inject using one method, for example you can remove the Sorter from your input parameter constructor like this `public BinarySearch() {` – Daniel C. Aug 28 '17 at 01:41
  • Also you can inject as a constructor parameter but in that case remove the Autowired and Qualifier form `Sorter sorter;` and put the Qualifier in the constructor like this `public BinarySearch(@Qualifier("quick") Sorter sorter) {` – Daniel C. Aug 28 '17 at 01:43
  • Okay the way without autowiring worked, but what if I want to use autowiring without Primary just Qualifier annotation and specify it the way I did? And why autowiring by name doesn't work? Sorry for the amount of questions but I am still learning. – CptPackage Aug 28 '17 at 01:48
  • its ok, you can use `@Qualifier` as many times as you need, `@Primary` is just an annotation to define a `default` injection just to tell spring how to decide what bean inject. `@Autowired` also work but in your example it had a mismatch with the constructor parameter because by default spring will take care of the parameter constructor of a `@Component` even if you don't put `@Autowired` to the constructor spring will try to inject it to the constructor parameter and also to the `@Autowired` members – Daniel C. Aug 28 '17 at 01:57
  • Thank you so much sir, I removed the constructor and it worked perfectly. Do you have a place where the autowiring and constructor part are explained in details? – CptPackage Aug 28 '17 at 02:02
  • sure, the must complete documentation is in Spring oficial site, after that you can find many tutorials at google, but first try to read from Spring oficial site this the link https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-annotation-config – Daniel C. Aug 28 '17 at 02:09
  • if you find that this answer is helpful I would really appreciate if you can accept the answer, otherwise just let me know if I have to improve the answer. – Daniel C. Aug 28 '17 at 02:22
5

Using the below piece of code

@Autowired
@Qualifier("quick")

Sorter sorter;

you are telling spring the instance of sorter should be qualified for "quick" bean. But in the below constructor:

public BinarySearch(Sorter sorter) {
    super();
    this.sorter = sorter;
}

you are not informing spring to which instance of Sorter should be used. As there are 2 bean qualifying for this so spring is throwing error. So either you put @Qualified("quick") annotation before the Sorter arg or remove the Sorter arg from the constructor. Hope this helps.

imnitesh
  • 83
  • 9