Spring Qualifiers

Categories: Java

Just a trivial note about use of the Spring annotation @Qualifier. It is most commonly used to inject a specific bean by referencing a (context-wide unique) bean-name. However:

  • the annotation can also be used at the bean-definition site, and
  • at the injection-site, only (type, qualifier) need to be unique

This usage of Qualifier was intended by the library authors, but is not very well documented.

When selecting a bean to inject, Spring needs to be able to select a single candidate from the bean context; it filters by type (ie ignores all beans that don’t match the injected type) and filters by qualifier (ignore all beans that don’t have a matching qualifier). As long as the result is a single bean, that’s fine.

Here’s a trivial spring-integration-test I wrote to demonstrate this:

package net.vonos.example;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
public class CmsDummyIT {
    @Configuration
    public static class Config {
        @Bean
        @Qualifier("foo")
        public String fooString() {
            return "fooval";
        }

        @Bean
        @Qualifier("foo")
        public Long fooLong() {
            return 3L;
        }

        @Bean
        @Qualifier("bar")
        public Long barLong() {
            return 4L;
        }
    }

    // ok; there are two objects qualified with "foo" but only one is a Long. Or alternately, two objects
    // of type Long, but only one is qualified with "foo"
    @Autowired
    @Qualifier("foo")
    protected Long fooLong;

    // ok; there are two objects qualified with "foo" but only one is a String
    @Autowired
    @Qualifier("foo")
    protected String fooString;

    // ok; returns both Long beans
    @Autowired
    protected List<Long> longs;

    // here the full bean-name is needed as there are two beans of type Object with qualifier "foo"
    @Autowired
    @Qualifier("fooLong")
    protected Object fooLongAsObj;

    @Test
    public void contextLoads() {
        Assert.assertTrue("Spring context loads", true);
    }
}