0

After upgrading from MyBatis 3.0.3 to 3.2.7 (and from mybatis-spring 1.0.0-RC3 to 1.2.2) I'm getting this exception in many (if not all) of my JUnit tests when they load a Spring Context

java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.foo.FooDao.java (full stack trace below)

This a a massive project with a ton of mapper XML files and a ton of Spring contexts. Here is an except of how I'm setting up MyBatis:

Spring Context

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${jdbc.foo.driverClassName}"
        p:url="${jdbc.foo.url}" p:username="${jdbc.foo.username}"
        p:password="${jdbc.foo.password}" p:defaultAutoCommit="true" />

<bean id="fooSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dataSource" />

<bean id="fooDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface"
            value="com.foo.FooDao" />
        <property name="sqlSessionFactory" ref="fooSqlSessionFactory" />
</bean>

DAO XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper>
    <select id="getIDs" resultType="string">
        select ID from foo where thing=#{bar}
    </select>
</mapper>

Full Stack Trace

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:312)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'nagDao' defined in file [D:\data\pchurchw\Desktop\eclipse\14.5.5-Inflation_Swap\linux\extractors\bin\com\rbccm\ccr\refdata\netting\dao\NagDao.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.foo.FooDAO.getIDs
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1482)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:608)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
    ... 25 more
Caused by: java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.foo.FooDAO.getIDs
    at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:100)
    at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1541)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1479)
    ... 40 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.foo.FooDAO.getIDs
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:92)
    at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.loadXmlResource(MapperAnnotationBuilder.java:164)
    at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:118)
    at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:71)
    at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:651)
    at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:97)
    ... 43 more
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.foo.FooDAO.getIDs
    at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:782)
    at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:754)
    at org.apache.ibatis.session.Configuration.addMappedStatement(Configuration.java:578)
    at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:288)
    at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:107)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:135)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:128)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:118)
    ... 49 more
AfterWorkGuinness
  • 1,780
  • 4
  • 28
  • 47
  • Add a namespace attribute to the mapper tag, say like and try to build. See whether the error message changes. – Akhil Sep 23 '14 at 19:54
  • I've got about 100 of these (not my design), should they all be in the same namespace of all different ? – AfterWorkGuinness Sep 23 '14 at 19:56
  • See basically what happens is.. mybatis needs a unique ID for every statement. Since some IDs may be named in multiple mappers, so they get conflicted. Namespaces basically saves us from these conflicts. so, the answer to your question is YES. You need to add namespaces to most of the files if not all. I myself had to do this for about 30 files for this error. But the error got resolved after doing this. – Akhil Sep 23 '14 at 20:01
  • That was the problem. Looks like namespaces were ignored in MyBatis 3.0.3. Can you post this as an answer so I can accept it ? Thanks ! – AfterWorkGuinness Sep 23 '14 at 20:42
  • I had a similar problem that required a different solution. https://stackoverflow.com/q/60112455/715269 – Gangnus Feb 07 '20 at 14:00

1 Answers1

3

Add a namespace attribute to the mapper tag, say like <mapper namespace="fooData">.

Basically what happens is.. mybatis needs a unique ID for every statement. Since some IDs may be named in multiple mappers, so they get conflicted. Namespaces basically saves us from these conflicts. So, You will need to add namespaces to most of the files if not all. The error shall be resolved now. :)

Akhil
  • 479
  • 3
  • 13