1

I am learning autowiring in Spring Boot using @Primary and @Qualifier annotations. I am able to understand that @Primary wires the annotated class as a dependency and in case more than one satisfying classes are found @Qualifier can come to help.

@Component
public class VehicleBean {

    @Autowired
    @Qualifier("car")
    Vehicle car;

    public void check() {
        car.details();
    }
    
    public Vehicle getCar() {
        return car;
    }
    
    public void setCar(Vehicle car) {
        this.car = car;
    }
    
}

Bike

@Component
//@Primary
@Qualifier("car")
public class Bike implements Vehicle {

    @Override
    public void details() {
        System.out.println("Bike is driving");
    }
    
}

Car

@Component
//@Primary
@Qualifier("bike")
public class Car implements Vehicle {
    @Override
    public void details() {
        System.out.println("Car is driving");
    }
}

When I add @Qualifier("car") on my autowired dependency named as "bike" and have @Qualifier("car") on Car and @Qualifier("bike") on Bike, it picks up Car. However, when I interchange the @Qualifier on Bike and Car(e.g - @Qualifier("bike") on Car and vice versa) it picks up the bike. Also when I change the @Qualifier to "bike on my autowired dependency named as "car" and have @Qualifier("car") on Bike and vice verse, it is picking Car. I was expecting Bike to be picked. What am I missing?

Community
  • 1
  • 1
mack
  • 345
  • 5
  • 18
  • Some comments on this question have been removed. Hence I am re posting my question - When I add @Qualifier("car") on my autowired dependency named as "car" and have @Qualifier("car") on Bike and @Qualifier("bike") on Car, it picks up Car and not bike. Why? – mack Jul 23 '19 at 09:28

2 Answers2

2

The use of qualifier annotation here is incorrect, the qualifier annotation is used on a field, a parameter or a method to pick the write candidate bean while authowiring,

This annotation may be used on a field or parameter as a qualifier for candidate beans when autowiring. (JAVA DOC)

In simple word, you define the beans by name and you tell spring what name to pick by adding @Qualifier, in your example you have to add the bean name in @Component.

@Component("bike")
public class Bike implements Vehicle {

    @Override
    public void details() {
        System.out.println("Bike is driving");
    }

}

@Component("car")
public class Car implements Vehicle {
    @Override
    public void details() {
        System.out.println("Car is driving");
    }
}

Coming to your question, why it picks Car? , because the AnnotationBeanNameGenerator generate a default name if no one specified and the built name is based on the short name of the class (with the first letter lower-cased):

If the annotation's value doesn't indicate a bean name, an appropriate name will be built based on the short name of the class (with the first letter lower-cased). For example:

com.xyz.FooServiceImpl -> fooServiceImpl (JAVA DOC)

hasnae
  • 2,137
  • 17
  • 21
  • what is wrong in use of the @Qualifier here? It is working for other scenarios as expected. – mack Jul 23 '19 at 12:50
  • `@Qualifer` doesn't have any affect on bean definitions as the JavaDoc states, it's only used when selecting beans during autowiring fields or method parameters. If you want to name your beans, do as @hasnae has suggested and pass the name into the `@Component` annotation. – Mike Jul 23 '19 at 13:09
  • Mike - If i have @Qualifier("bike) on Car and @Qualifier("car") on Bike Classes with no name defined at @Component, when I autowire bike attribute with @Qualifier("car"), it is picking bike. When i change the @Qualifier("car") to @Qualifier("bike"), it still picks bike Why? This is what i need to understand. What I am not able to relate is actually the latter when i change the qualifier to bike, i was expecting it to pick Car as the Class has been annotated with bike. – mack Jul 24 '19 at 07:56
  • 1
    As I mentioned in the end, if no name defined spring generate a default name, in your case it is car for Car class and bike for Bike class. And as mike said @Qualifier has no effect on class level you can omit it – hasnae Jul 24 '19 at 08:06
-1

@Qualifier annotation won't work here @Component @Qualifier("car"). It can be used on a field, a parameter or a method for autowiring.
You need to pass the name with @Component annotation only, like @Component("car")

  • @Qualifier does work at class level. See section 7.10.8 in spring documention - https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#beans-generics-as-qualifiers When relying upon classpath scanning for autodetection of components, you provide the qualifier metadata with type-level annotations on the candidate class – mack Jul 23 '19 at 12:55