Arul
Arul

Reputation: 183

Spring factory - NoUniqueBeanDefinitionException:

I am trying to implement factory pattern to get producer from a list of available ones. While doing it i am getting the below exception. Not able to figure out the issue with the code. Can you please let me know what i am missing.

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.interfaces.Producer] is defined: expected single matching bean but found 2: A,B

Please find the code below

    public interface Producer<T>  {
    public void start();
    public List<T> produce() throws CEHServiceException;
    public void stop();
}

@Component("A")
public class ProducerA extends Producer  {
    //Autowire Services & Properties

}

@Component("B")
public class ProducerB extends Producer  {
    //Autowire Services & Properties
}

@Configuration
public class AgentConfiguration {
    @Bean
    public ServiceLocatorFactoryBean createProducerFactoryBean(){
        ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
        bean.setServiceLocatorInterface(ProducerFactory.class);
        return bean;
    }
}

public interface ProducerFactory {

    Producer getProducer(String producerName);

}

@Component
public class AdvancedAgentProcessor {

    @Autowired
    private ObjectFactory<AdvancedRunnerImpl> runnerFactory;
    public void init(){
        AdvancedRunnerImpl runner = runnerFactory.getObject();
        runner.setProducerName("A");
        runner.start();
    }

}


@Component
@Scope("prototype")
public class AdvancedRunnerImpl implements Runner {

    @Autowired private ProducerFactory producerFactory;
    private Producer producer;
    private String producerName;

    public void start() {
        producer = producerFactory.getProducer(this.producerName);
    }

}

Full stack tracke

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.etl.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
    at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invokeServiceLocatorMethod(ServiceLocatorFactoryBean.java:377)
    at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invoke(ServiceLocatorFactoryBean.java:363)
    at com.sun.proxy.$Proxy34.getProducer(Unknown Source)
    at com.test.runner.AdvancedRunnerImpl.start(AdvancedRunnerImpl.java:54)
    at com.test.app.AdvancedAgentProcessor.init(AdvancedAgentProcessor.java:48)
    at com.test.app.DataAgentApplication.main(DataAgentApplication.java:25)

Upvotes: 1

Views: 5115

Answers (3)

borjab
borjab

Reputation: 11655

Spring does not know which component to autowire. It seems that the problem is in the ProducerFactoryImplementation but we cannot see it.

There are three possible solutions:

  1. Use Qualifiers so you can tell Spring which specific implementation you want.There is an example in StackOverflow here

  2. Use the Primary annotation (See more here3). That means that in case of ambiguity Spring will give priority to the @Primary annotated component

  3. Autowire a list of beans. Something like:

    @Autowired private List<Producer> myAvalilableProducers;
    
    public Producer getByName(name){
    
        for( Producer producer: myAvalilableProducers){
            if(producer.getName().equals(name)){ return producer; }
        }
        throw new RuntimeException("No producer with name " + name " found");
    }
    

This third option more useful when you do not know the specific instance at compile time or if you really want to inject a list of components.

Upvotes: 2

Suprita Athale
Suprita Athale

Reputation: 1

This happens when the dynamic proxy is not able to pick the correct Bean. Please check whether this.producerName is null or empty.

Upvotes: 0

Raedwald
Raedwald

Reputation: 48694

You have two beans that extend Producer. Somewhere you are trying to autowire a Producer. Spring does not know which Producer to use.

Upvotes: 0

Related Questions