views:

83

answers:

4

Hi

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?
A: 

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.

Bozho
Thanks for the answer, however, I tried but it didn't work :-(
_how_ it didn't work?
Bozho
I get exactly the same error. Please, hold on a a minute, I will pack the whole source code and put it somewhere for download ...
Ho Bozho. I have put two packages for download: http://drop.io/sof20100708_1 One is working fine (testspringanno.works.zip) and the other one produces the error (testspringanno.error.zip). Latter features an additional package called "de.sandbox.test.hibernatedao". The full error message is located in testspringanno.error/target/surefire-reports/de.sandbox.test.dao.BodyStatDAOTest.txt
O, btw, I tried something like `@Resource(name = "jpaUserDAO") private IBodyStatDAO userDAO;` and it did not change anything. Even not after explicitly defining the bean id in the appcontext.xml :-(
A: 

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 ?

+2  A: 

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.

iwein
And I carried on using @Autowired rather than @Resource?
@Resource is less flexible than @Autowired. I'd only use it if you can't have a Spring dependency in the class you're wiring with it, and if you are using spring to wire EJBs. Your test case has no business with it, particularly since the latest versions of Spring 3 support autowiring disambiguation on matching field names.
iwein
+1  A: 
  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.

Sam Brannen