If you have a trailing space in the alias attribute of a typeAlias definition, like this:
<typeAliases>
<typeAlias alias="User " type="com.example.domain.User" />
</typeAliases>
at runtime you get an exception like this:
java.lang.IllegalArgumentException: Result Maps collection already contains value for com.example.persistence.UserMapper.mapper_resultMap[xxx]_association[xxx]
where the map and association referenced in the exception are ones defined in your mapper.
Removing the trailing space fixes the problem, but it took a long time to track down.
Can you post your resultmap? When using that in the default test I get an expected result
org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in org/apache/ibatis/submitted/basetest/Mapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'user'. Cause: java.lang.ClassNotFoundException: Cannot find class: user
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:51)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:35)
at org.apache.ibatis.submitted.basetest.BaseTest.setUp(BaseTest.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
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.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'user'. Cause: java.lang.ClassNotFoundException: Cannot find class: user
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:106)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:89)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:49)
... 17 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'user'. Cause: java.lang.ClassNotFoundException: Cannot find class: user
at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:114)
at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:89)
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.loadXmlResource(MapperAnnotationBuilder.java:159)
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:113)
at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:66)
at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:650)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:326)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:104)
... 19 more
Caused by: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'user'. Cause: java.lang.ClassNotFoundException: Cannot find class: user
at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:100)
at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:69)
at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:129)
at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:122)
at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:112)
... 26 more
Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'user'. Cause: java.lang.ClassNotFoundException: Cannot find class: user
at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:114)
at org.apache.ibatis.builder.BaseBuilder.resolveAlias(BaseBuilder.java:127)
at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:98)
... 30 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: user
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:188)
at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:87)
at org.apache.ibatis.io.Resources.classForName(Resources.java:254)
at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:110)
... 32 more
Here is a sample resultmap:
<resultMap id="caseMap" type="Case">
<id property="id" column="case_id" javaType="int" jdbcType="INTEGER"/>
<result property="comment" column="case_comment" javaType="String"/>
</resultMap>
<resultMap id="patientMap" type="Patient">
<id property="id" column="pat_id" javaType="int" jdbcType="INTEGER"/>
<result property="firstName" column="pat_first" javaType="String"/>
<result property="lastName" column="pat_last" javaType="String"/>
</resultMap>
The Patient alias is the one with the trailing space in the alias definition. If I reference the patientMap via an association in caseMap, I get the same exception as you. I get the IllegalArgumentException exception when the patientMap isn't referenced.
Still unable to reproduce it. I am using the base test:
https://code.google.com/p/mybatis/wiki/Test
<typeAliases>
<typeAlias type="org.apache.ibatis.submitted.basetest.User" alias="User"/>
<typeAlias type="org.apache.ibatis.submitted.basetest.Product" alias="Product "/>
</typeAliases>
<resultMap type="User" id="usermap">
<association property="product" resultMap="productmap" />
</resultMap>
<resultMap type="Product" id="productmap">
</resultMap>
Try removing the association from the usermap. That should mimic what I had. The IllegalArgumentException came about when the result map with the extra space was not referenced by another resultmap.
Yep, I that's what I tested but... got "cannot find class Product"
I think I'll need to create an example test / project then. It will be at a couple days before I can get to it, though.
Thank you!
Better fork mybatis-3 and add a new package following the BaseTest case.
Although I could recreated this easily in my project, I could not do so as a MyBatis test case. I got the same result as you. Then I noticed that the test case explicitly lists the mappers, while my project is using org.mybatis.spring.mapper.MapperScannerConfigurer to find the mappers automatically. When I added the mapper explicitly I got the CNF exception as you did.
So I tried recreating the test under mybatis-spring with pretty much the same result. At this point I'm going to give up on trying to recreate the problem. Maybe one of the third-party libraries I'm using is having a strange impact on MyBatis. If I find out any more information I'll post here, but you might as well close this as "won't fix" since I can't come up with a test case.
Hi again. First of all big thanks for reporting the bug and trying to get that test.
Probably the problem is in the MapperScanner or more precisely in how Spring loads and autowires beans.
Seems that on certain circumstances Spring re-tries the creation of a bean in case the first attempt failed. Proably this is an algorithm to resolve circular depencencies.
When MyBatis fails to startup it probably gives th right exception but if you (Spring) attempt to add another element to a wrong configuration, then a second exception is thrown but this one... may not be related to the real problem.
MyBaitis loading is not "transactional". Imagine the loading works like this:
Spring calls MB to register a mapper:
Spring calls again MB to register the same mapper:
Looks a lot like the problem you saw. And unfortunately I was not able to find a solution for this. And I am afraid the fix should go in Spring rather than in MyBatis.
Hope this clarifies the situation.
Thank you!!
I had the same problem while I run my project over JRebel. When I run without it I didn't have such problem.
It was in SqlSessionFactoryBean
- <property name="mapperLocations" value="classpath*:sql-mybatis/*.xml" />
+ <property name="mapperLocations" value="classpath:/sql-mybatis/*.xml" />
This happens to me myself yesterday! :)
I have opened an issue in Spring to see if there is something we can do in the Scanner to avoid this problem.
Hi,
Has there been a resolution to this issue?
Im updating from spring 3.1 to 4.1.6
mybatis 3.0.6 to 3.3.0
I get the issue with or without jrebel running. Im using the spring configuration.
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mapperpackage" />
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
Hi Eduardo,
Has there any solution?
I get this issue on the server start sometimes. And following my spring configuration
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage"
value="com.sample.business.**.mapper; com.sample.framework.**.mapper;" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
Hi mybatis team!
I got the issue in the following case:
When application is starting then:
<mappers>MappedStatement map,incompleteStatements collection.MappedStatement map:getMappedStatement(String id) and buildAllStatements() methods.buildAllStatements() always checks incompleteStatements collectionMappedStatement map:org.apache.ibatis.session.Configuration
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);
}
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.get(id);
}
/*
* Parses all the unprocessed statement nodes in the cache. It is recommended
* to call this method once all the mappers are added as it provides fail-fast
* statement validation.
*/
protected void buildAllStatements() {
if (!incompleteStatements.isEmpty()) {
synchronized (incompleteStatements) {
// This always throws a BuilderException.
incompleteStatements.iterator().next().parseStatementNode();
}
}
I fixed it by eliminating <mappers> tag from mybatis configuration. Mybatis loads xml and interfaces without this tag. Also the issue can be fixed by specifying interface mappers before xml mappers in configuration, to get loading order.
But, there is concern:
if mybatis has collection incompleteStatements then should process this case correctly.
Hello, Is there any updates on the above issue? I am using mybatis 3.1.1 with SPring 3.2.0-RELEASE and everything works fine. Once I upgrade mybatis say 3.2.4 or even 3.4.6-SNAPSHOT , I am getting this only for 2 of the 40 mappers that are present.
Update - Tried with Spring 4.1.5-RELEASE and get the same result!
@emacarron can you please let me know if this has been resolved with any version of Spring ?
Appreciate your help!
Hi, for me the problem was adding Tomcat's classpath the directory un level up the one with xml mappers.
My case was (with sample directory structure):
src/main/resources/mybatis
--- mapper1.xml
--- mapper2.xml
etc...
but in the classpath I set
src/main/resources
That caused the problem.
Logs showed the error for the first parsed mapper; I tried removing it but the error appeared again.
Changing classpath variable to
src/main/resources/mybatis
solved the problem.
Hope this helps.
Most helpful comment
I had the same problem while I run my project over JRebel. When I run without it I didn't have such problem.
It was in SqlSessionFactoryBean