Skip to content
Advertisement

@Qualifier in Spring on top of classes

I’ve been playing around in Spring/Spring Boot and notice something strange which I can’t really dig on my own, so any help would be appreciated.

Let’s say we have the following

public interface ICar {}
@Component
public class CarOne implements ICar {}
@Component
public class CarTwo implements ICar {}
public class Driver {
        
    @Autowired
    private ICar car;

}

I am running a Spring Boot program, so everything is set up correctly, this is for simplicity. At this point, if we run our program we would get an exception, because of the ambiguity. Now according to https://www.baeldung.com/spring-qualifier-annotation if we add @Qualifier on top of a @Component class, it should change the bean name of this class. So for example, if we change the CarOne class to:

@Component
@Qualifier("car")
public class CarOne implements ICar {}

The bean name should be car.

Based on Spring documentation, @Autowired uses the field name as a default qualifier if not provided any, thus we should be able to successfully run our program, since the @Autowired field in class Driver is looking for a bean named car and we already have one. Not this is happening tho. I again receive the same exception, regarding ambiguity. Now if I add @Qualifier("car"), along with @Autowired, everything will run normally.

I am confused, because if we change for example the @Autowired field to carOne or carTwo (without adding any @Qualifier on top of the @Component classes), again the program will run correctly. I guess this is related somehow with the type/name difference, but can’t figure it out. Can somebody with a bit more knowledge explain why this could be happening?

P.S: I am referring to the baeldung article, since I couldn’t find anything better in the official Spring doc, regarding the usage of @Qualifier on top of classes.

Advertisement

Answer

Using @Qualifier on a component doesn’t change the name. It adds, as the name implies, a qualifier to the metadata of the bean. This metadata (the qualifier) can be used to select which instance of a class to use.

So if you annotated one of them with @Qualifier("car") you need to add that to the injection point as well (if that is the one you want).

You could also use @Qualifer as a meta annotation, meaning you could create an annotation with this annotation and use that as the metadata.

Something like

@Qualifier
public @interface SimpleCar {}

Now you could annotate your CarOne (for example) with @SimpleCar and put that on the @Autowired field as well. Which is probably clearer as using names/strings to qualify things.

You could also use @Qualifier("carOne") on the @Autowired field to specify which to use (as the name of the bean is used as a fallback). However the drawback is you need to know the name (hence preferred is to use specific qualifier annotations).

Now for @Autowired it works by default on type. So it will try to find a single Car instance in this case. You have more than that, and so it will, as a fallback, try to match the name of the field to a name of a bean (car here) as that isn’t the case it will fail. If you change the CarOne to @Component("car") it will also work without further change as you now have a bean matching the type and name of the field. However again relying on this is generally a bad idea (one change in naming strategy, class name and things break).

Advertisement