org.springframework.beans.factory.NoUniqueBeanDefinitionException: expected single matching bean but found 3

0

How to resolve ambiguities in the AUTOMATIC CONNECTION of Bean in Spring? Image we have an interface:

public interface Dessert {
    void eat();
}

And we have three Beans that implement the interface:

BEAN CAKE:

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

BEAN COOKIE:

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

BEAN ICECREAM:

@Component
public class IceCream implements Dessert{
    @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);
        Dessert dessert = ctxt.getBean(Dessert.class);
        dessert.eat();
        ctxt.close();

    }

}

The program throws the following exception: Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'Dessert' available: expected single matching bean but found 3: cake, cookies, iceCream     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean (DefaultListableBeanFactory.java:1041)

This happens because we have three desserts and Spring does not know which of them we want to eat.

How can we resolve the ambiguity and tell spring which of the Desserts do we want it to believe, to eat it?

    
asked by Santiago Celada Gonzalez 01.09.2018 в 15:47
source

1 answer

2

To solve the ambiguity you need to specify to spring what will be your concrete implementation in your case Cake, Cookie or IceCream.

Example

 Dessert dessert = ctx.getBean(Cookie.class);
 dessert.eat();

This series of "problems" can also be seen when you do dependency injection using the @Autowired annotation in cases where you have an interface and multiple implementations.

Example

@SpringBootApplication
public class DemoApplication {


    @Autowired
    Dessert dessert;

    public static void main(String[] args) {


        SpringApplication app;
        app = new SpringApplication(DemoApplication.class);
        // SpringApplication.run(DemoApplication.class, args);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);


    }

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {

            dessert.eat();
        };
    }
}

In the same way that your original example would show us the following message: required a single bean, but 3 were found , to correct the problem it would be enough to use the annotation @Primary on top of which bean which has the preference to be injected or Use annotation @Qualifier although the latter has a wider utility.

@Component
@Primary
public class Cake implements Dessert {
    @Override
    public void eat() {
        System.out.println("Eating a Cake !!!!");

    }
}
    
answered by 01.09.2018 / 17:31
source