org.springframework.beans.factory.UnsatisfiedDependencyException org.springframework.beans.factory.NoUniqueBeanDefinitionException

1

How to resolve ambiguities in the AUTOMATIC CONNECTION of Bean in Spring? Image we have a Dessert interface, and we have three different desserts (Beans) that implement the interface (Dessert).

The dessert of the day is Cookie, so we wrote it down as a favorite with @Primary .

The problem is that the desserts have been made just and if someone wants to repeat dessert, there will be no more cookies, so we have created "repeatDessert" for those who want to repeat dessert.

In addition to the favorite dessert, there are two more desserts, CAKE AND ICECREAM.

We want everyone who repeats to be served IceCream dessert, of which we have enough.

How can we tell Spring which of the two desserts is that we want it to serve?

public interface Dessert {
    void eat();
}

BEAN CAKE:

@Component
public class Cake implements Dessert{

    private Dessert repeatDessert;

    public Dessert getRepeatDessert() {
        return repeatDessert;
    }

    @Autowired
    public void setRepeatDessert(Dessert repeatDessert) {
       this.repeatDessert = repeatDessert;
    }

    @Override
    public void eat() {
        System.out.println("Eating a Cake !!!!");
    }
}

BEAN COOKIE:

@Component
@Primary
public class Cookie implements Dessert{

    private Dessert repeatDessert;

    public Dessert getRepeatDessert() {
        return repeatDessert;
    }

    @Autowired
    public void setRepeatDessert(Dessert repeatDessert) {
       this.repeatDessert = repeatDessert;
    }

    @Override
    public void eat() {
        System.out.println("Eating a Cookie !!!!");
    }
}

BEAN ICECREAM:

@Component
public class IceCream implements Dessert{

    private Dessert repeatDessert;

    public Dessert getRepeatDessert() {
        return repeatDessert;
    }

    @Autowired
    public void setRepeatDessert(Dessert repeatDessert) {
       this.repeatDessert = repeatDessert;
    }

    @Override
    public void eat() {
        System.out.println("Eating a IceCream !!!!");
    }
}

This would be the configuration file:

@Configuration
@ComponentScan
public class AutoBeanConfiguration {

}

This would be the Main class:

public class Main {

    public static void main(String[] args) {
        BasicConfigurator.configure();
        Logger.getRootLogger().setLevel(Level.ERROR);
        AnnotationConfigApplicationContext ctxt = new AnnotationConfigApplicationContext(AutoBeanConfiguration.class);
        Cookies cookies = ctxt.getBean(Cookies.class);
        cookies.eat();
        Dessert dessert = cookies.getRepeatDessert();
        dessert.eat();
        ctxt.close();
    }

}

The program throws the following excepcion :

Exception in thread "main" Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cookies': Unsatisfied dependency expressed through method 'setRepeatDessert' parameter 0;
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'Dessert' available: expected single matching bean but found 2: cake,iceCream

How can we resolve the ambiguity and tell spring which of the Desserts do we want to create, when we want to repeat?

The console output should be this:

Eating a Cookies !!!!
Eating a IceCream !!!!
    
asked by Santiago Celada Gonzalez 02.09.2018 в 14:40
source

1 answer

2

As it appears in the error, your failure is that when you try to inject a Dessert in setRepeatingDessert , Spring does not know what implementation of Dessert you refer.

You can fix it using @Qualifier , which allows you to specify which bean you want to inject. By default, it uses the name of the bean class in lowerCamelCase, as if it were a variable:

@Autowired
public void setRepeatingDessert(@Qualifier("iceCream") Dessert repeatingDessert) {
    this.repeatingDessert = repeatingDessert;
}

Cookie dessert = ctxt.getBean(Cookie.class);

System.out.println(dessert.eat());  // "Eating cake!!"
System.out.println(dessert.getRepeatingDessert().eat()); // "Eating ice cream!!"

You can also give your bean a personalized name, again with the @Qualifier tag, this time in the class declaration:

@Component
@Qualifier("remainingDessert")
public class IceCream implements Dessert{

    // Clase IceCream
}

But then remember that the qualifier that you use at the injection point must be in agreement:

@Autowired
public void setRepeatingDessert(@Qualifier("remainingDessert") Dessert repeatingDessert) {
    this.repeatingDessert = repeatingDessert;
}

Cookie dessert = ctxt.getBean(Cookie.class);

System.out.println(dessert.eat());  // "Eating cake!!"
System.out.println(dessert.getRepeatingDessert().eat()); // "Eating ice cream!!"
    
answered by 03.09.2018 / 11:35
source