0

I'm using Spring 3.0 with a genericDAO. I have this:

public interface GenericDAO<T, ID extends Serializable>
...
@Repository("genericDAO")
public class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {
...
public interface A extends GenericDAO<Turno, Long> {
...
public interface B extends GenericDAO<TipoTurno, Long> {
...
@Repository("A")
public class AImpl extends GenericDAOImpl<TipoTurno, Long>  implements A{
...
@Repository("B")
public class BImpl extends GenericDAOImpl<TipoTurno, Long>  implements B{

But when I try to get them injected as follow:

@Autowired
A a;

I get:

expected single matching bean but found 3: [genericDAOImpl, A, B]

I can't understand why. I also tried to do it with

@Resource(name="A")

and even

@Resource(type=A.class)

I also tried using @Qualifier but I always get the same exceptions, it looks like Spring is always looking for GenericDao and not the specific class.

but it's still not working. And I can't understand why.

Any suggestions?

Thank you very much.

CalamarBicefalo
  • 87
  • 2
  • 11
  • Are you sure you get the same error message in all three cases? I can see how you could get the "expected single matching bean" message in the @Autowired case, but definitely not in the @Resource(name="A") case. Is it possible that you annotated both the getter and the member variable? – John Watts Jun 18 '12 at 12:03
  • Thank you very much for your help. I've doubled checked it to answer you and yes, when i use @Resource(name="specific_name") i get org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [xxx.model.entities.dao.GenericDAO] is defined: expected single matching bean but found 3: [genericDAO, A, B]. About your question i haven't annotated the getter. – CalamarBicefalo Jun 18 '12 at 12:21
  • @CalamarBicefalo qualifer name is same as interface, this is wrong – NimChimpsky Jun 18 '12 at 12:23
  • @NimChimpsky, I've changed qualifier name, instead of A i set cat, instead B i set dog, and it fails again saying this time: expected single matching bean but found 3: [genericDAO, cat, dog]. I tried it doing it with @Resource(name="cat"). – CalamarBicefalo Jun 18 '12 at 12:32
  • 2
    Remove @Repository("genericDAO") annotation. You wont need to define it as bean. – Sunil Chavan Jun 18 '12 at 12:53

2 Answers2

1

I reproduced your exact error message and then fixed it. Here is exactly the source code I used, minus package names. I recommend copying it, running it and diffing it with yours. One difference I noticed is that as written in the question, AImpl does not compile. It implements both GenericDAOImpl and GenericDAO. I changed the first generic parameter to Turno, to make it compile. I assume this was a typo. I reproduced exactly your error when I initially set all the fields to @Autowired. Then I added @Qualifier("genericDAO") and it wired all three successfully.

public interface GenericDAO<T, ID extends Serializable> {}
...
@Repository("genericDAO")
public class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {}
...
public interface A extends GenericDAO<Turno, Long> {}
...
public interface B extends GenericDAO<TipoTurno, Long> {}
...
@Repository("A")
public class AImpl extends GenericDAOImpl<Turno, Long> implements A {}
...
@Repository("B")
public class BImpl extends GenericDAOImpl<TipoTurno, Long>  implements B {}
...
public class TipoTurno {}
...
public class Turno {}
...
@Component
public class Thingy {
    @Autowired
    private A a;

    @Autowired
    private B b;

    @Autowired
    @Qualifier(value="genericDAO")
    private GenericDAO genericDao;
}
...
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("genericdao.xml");
        context.getBean(Thingy.class);
    }
}
...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:annotation-config/>
    <context:component-scan base-package="genericdao"/>
</beans>

Note that the actual error message is longer than the one you provided. It is important to read the whole thing looking for causes. Spring loves exception stack traces with 5, even 10 levels of causes. Here is the relevant substring of the message I get:

Could not autowire field: genericdao.GenericDAO genericdao.Thingy.genericDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [genericdao.GenericDAO] is defined: expected single matching bean but found 3: [A, B, genericDAO]

It indicates that the field that was not being autowired was Thingy.genericDao, not Thingy.a. I strongly suspect this is the case for your error as well.

John Watts
  • 8,717
  • 1
  • 31
  • 35
  • It did it. In fact the problem was that I was trying to Inject a 'genericDAO' without qualifying it. But it was making me crazy because i was looking to solve it in the specific injections. Thank you very much @John Watts, it's nice so much help. I cant vote up your answer because i have no reputation :'( – CalamarBicefalo Jun 19 '12 at 10:50
  • You're welcome. Thanks for accepting the answer. I hope the comment about spring exceptions is helpful. Although they often contain the necessary information it can get lost in a sea of causes. – John Watts Jun 19 '12 at 10:58
  • Reading exception trace carefully was the way i found my mistake, so yes, your comment was really helpful. – CalamarBicefalo Jun 19 '12 at 11:03
0
@Repository("AImpl")
public class AImpl extends GenericDAOImpl<TipoTurno, Long>  implements A{
...
@Repository("BImpl")
public class BImpl extends GenericDAOImpl<TipoTurno, Long>  implements B{
...
@Resource(name = "AImpl")
A whatever; //I would normally call it aImpl

As long as the qualifier names match up you should be good to go. The error is caused by autowiring the injection, where the interface is implemented twice.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • Thank you NimChimpsky, but as said, I get exactly the same exception when using both @Resource(name= "specific_name") and @Resource(type=specific_class.class) – CalamarBicefalo Jun 18 '12 at 12:25
  • @CalamarBicefalo Look at what I have changed. Your interface name is the same as qualifer this causes the problem. Doing it the way I outlined works fine. – NimChimpsky Jun 18 '12 at 12:27
  • As said in my last reply, it is still not working. But anyway thank you very much @NimChimpsky. I've tried it with both Implementation name and random name. – CalamarBicefalo Jun 18 '12 at 12:36
  • @CalamarBicefalo I can't replicate this at all. You are injecting using the qualifer name ? GenericDAO is "implemented twice" on AImpl - this would cause problems when autowiring. – NimChimpsky Jun 18 '12 at 12:47
  • @CalamarBicefalo you need to remove the autowired injection. And only use qualifier injection. And look to refactor, its somewhat complex desgin of api – NimChimpsky Jun 18 '12 at 13:05