This is not the purpose of @Qualifier annotation to use it when getting beans through ApplicationContext. But since you need these or similar functions for some reason, I offer a workaround.
Create the annotation @Wanted and @NotWanted :
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Wanted { }
and
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface NotWanted { }
Annotate bean classes with these new annotations:
@Component @NotWanted public class NotWantedService implements Service {}
and
@Component @Wanted public class WantedService implements Service {}
Then you should add 2 methods somewhere where you have access to the ApplicationContext :
ApplicationContext applicationContext; private <T> Collection<T> getBeansByTypeAndAnnotation(Class<T> clazz, Class<? extends Annotation> annotationType){ Map<String, T> typedBeans = applicationContext.getBeansOfType(clazz); Map<String, Object> annotatedBeans = applicationContext.getBeansWithAnnotation(annotationType); typedBeans.keySet().retainAll(annotatedBeans.keySet()); return typedBeans.values(); } private <T> Optional<T> getBeanByTypeAndAnnotation(Class<T> clazz, Class<? extends Annotation> annotationType) { Collection<T> beans = getBeansByTypeAndAnnotation(clazz, annotationType); return beans.stream().findFirst(); }
And now you can use them to get beans or a single bean by annotation and type something like this:
Collection<Service> services = getBeansByTypeAndAnnotation(Service.class, Wanted.class);
or
Service service = getBeanByTypeAndAnnotation(Service.class, Wanted.class);
This may not be the best way to deal with the problem. But since we cannot get beans from ApplicationContext using the qualifier and type out of the box, this is one way to do this.