121

Suppose I have interfaces such as these:

interface Country {}
class USA implements Country {}
class UK implements Country ()

And this snippet of configuration xml:

<bean class="USA"/>
<bean id="country" class="UK"/>
<bean id="main" class="Main"/>

How can I control which dependency is autowired below? I'd like the UK one.

class Main {
    private Country country;
    @Autowired
    public void setCountry(Country country) {
        this.country = country;
    }
}

I am using Spring 3.0.3.RELEASE.

phs
  • 10,687
  • 4
  • 58
  • 84
Maniganda Prakash
  • 4,702
  • 8
  • 34
  • 42
  • Thought I would add that I was getting a "No unique bean of type..." in one (test) environment and it worked fine in my development environment. I am sure it was some kind of classpath thing, but turned out, if you add the @Qualifier, it worked fine. – markthegrea Feb 17 '12 at 13:51

5 Answers5

132

This is documented in section 3.9.3 of the Spring 3.0 manual:

For a fallback match, the bean name is considered a default qualifier value.

In other words, the default behaviour is as though you'd added @Qualifier("country") to the setter method.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • When you say "bean name", do you mean the name of the field which will contain the bean? (i.e. in this case `country`) – Nic Sep 17 '18 at 19:15
77

You can use the @Qualifier annotation

From here

Fine-tuning annotation-based autowiring with qualifiers

Since autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring's @Qualifier annotation. This allows for associating qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument. In the simplest case, this can be a plain descriptive value:

class Main {
    private Country country;
    @Autowired
    @Qualifier("country")
    public void setCountry(Country country) {
        this.country = country;
    }
}

This will use the UK add an id to USA bean and use that if you want the USA.

Paul Whelan
  • 16,574
  • 12
  • 50
  • 83
13

Another way of achieving the same result is to use the @Value annotation:

public class Main {
     private Country country;

     @Autowired
     public void setCountry(@Value("#{country}") Country country) {
          this.country = country;
     }
}

In this case, the "#{country} string is an Spring Expression Language (SpEL) expression which evaluates to a bean named country.

Ricardo Veguilla
  • 3,107
  • 1
  • 18
  • 17
  • 1
    can that be injected based on property? what if USA or UK is some kind of parameter coming from URL and I want to inject 2 different things based on what the param is? – Kalpesh Soni Apr 09 '15 at 22:31
7

One more solution with resolving by name:

@Resource(name="country")

It uses javax.annotation package, so it's not Spring specific, but Spring supports it.

theme
  • 361
  • 5
  • 7
6

in some case you can use annotation @Primary.

@Primary
class USA implements Country {}

This way it will be selected as the default autowire candididate, with no need to autowire-candidate on the other bean.

for mo deatils look at Autowiring two beans implementing same interface - how to set default bean to autowire?

Community
  • 1
  • 1
Mykhailo Dmytriakha
  • 628
  • 1
  • 7
  • 13