Question

I would like to use two different implementations for a DAO with Spring's testframework.

src.main.java

.businessobjects
   \-User.java
.dao
   \-IUserDAO.java
.daojpa
   \-UserDAO.java
.daohibernate
   \-UserDAO.java

The spring testcase in:

src.test.java.base:

package base;

import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/hibernate-beans.xml")
@Transactional
public abstract class SpringTestCase {}

And here is the error:

Caused by: java.lang.IllegalStateException: Annotation-specified bean name 'userDAO' for bean class [jpadao.UserDAO] conflicts with existing, non-compatible bean definition of same name and class [jpaadao.UserDAO]

I have already tried to override the autowiring by using qualifiers, e.g.:

<bean class="jpaadao.UserDAO">
    <qualifier value="jpaa"/>
</bean>
<bean class="jpadao.UserDAO">
    <qualifier value="jpa"/>
</bean>

And then in the testcase wiring with

@Autowired
@Qualifier("jpa")
private IUserDAO userDAO;

but the error persists.

Two questions:

  1. How can this problem be solved with annotation based configuration?
  2. How can I run tests WITHOUT autowiring and annotations?
Was it helpful?

Solution

You're using beans without names so that Spring will try to come up with a name, this name may be based on the @Component annotation that you presumably have on your class, but it could also be the camelcased version of your the unqualified class name of your bean (in both cases they would turn out equal and that causes Spring to object).

Also, it seems you are mixing component scanning and xml configuration in a way that looks a bit odd to me.

There are many ways out of this, but most cleanly you would use only a single bean implementing the contract you're trying to fullfil. If you do need different implementations you should give them different and more discriptive names:

<bean id="jpaUserRepository" class="..JpaUserRepository"/>

This will give you more useful logging, even if the bean names are never used because you rely on auto wiring.

OTHER TIPS

  1. Do what Iwein suggested: name your implementation classes better (e.g., HibernateUserDao and JpaUserDao); or specify a unique bean name via the @Component or @Repository annotation on your UserDAO implementation classes.
  2. You cannot currently run tests without autowiring. See this JIRA issue for details: https://jira.springsource.org/browse/SPR-6050

Regards,

Sam (author of the Spring TestContext Framework)

p.s. No, the problem you are facing is not related to SPR-4524.

You can try injecting the dependency by-name using the @Resource annotation. You will have to give names (ids) to the beans or use the default, which is the uncapitalized unqualified class name.

I've got it up and running now! However, I don't believe this is best practice. I simply excluded the path of the unwanted DAOs by writing into appContext.xml:

   <context:component-scan base-package="test">
        <context:exclude-filter type="regex" expression="test\.daohibernate.*"></context:exclude-filter>
    </context:component-scan>

Any suggestions? Could this issue be related to http://jira.springframework.org/browse/SPR-4524 ?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top