Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MyBatis - Mapped Statements collection already contains value for

I had the following error messages thrown when registering the mapper classes on my server startup,

[artifact:mvn] 2016-05-07 11:39:21,708 [ERROR] org.mybatis.spring.mapper.MapperFactoryBean - Error while adding the mapper 'interface com.sample.mappers.UserMapper' to configuration.
[artifact:mvn] java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.sample.mappers.UserMapper.getAllUsers
[artifact:mvn]  at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:802)
[artifact:mvn]  at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:774)
[artifact:mvn]  at org.apache.ibatis.session.Configuration.addMappedStatement(Configuration.java:598)
[artifact:mvn]  at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:300)
[artifact:mvn]  at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parseStatement(MapperAnnotationBuilder.java:313)
[artifact:mvn]  at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:128)
[artifact:mvn]  at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:72)
[artifact:mvn]  at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:671)
[artifact:mvn]  at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:81)
[artifact:mvn]  at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)

I used annotations for my mapper interfaces and there's no xml configuration.

Below is my UserMapper interface,

public interface UserMapper {

  @Select("SELECT  * FROM customer")
  List<User> getAllUsers();

  @Select("SELECT * FROM customer where userId = #{userId} ")
  List<User> getAllUsers(Long userId);

}
like image 616
Lucky Avatar asked May 07 '16 07:05

Lucky


2 Answers

I found out the cause of the error message. If you have the same method name, then mybatis throws the Mapped Statements collection already contains value error message. So the solution is to have different method names for different mapper statements even if the method signatures are different.

So In my mapper interface the method names second getAllUsers() name should be getUserById();. The same error is thrown if you have the same method name in any of the mapper.xml files. So it is mandatory to have unique method names or mapper namespace for different sql statements for mybatis to map this at runtime.

like image 149
Lucky Avatar answered Oct 17 '22 03:10

Lucky


In my case, the occurance was due to resultMaps were added to the Configuration after addition of mapper.

Eg:

Configuration configuration = new Configuration(environment);
configuration.addMappers("com.hemant.data.mapper");
configuration.addResultMap(getResultMapForRoles(configuration));

If we observe MyBatis source code, then on configuration.addMappers(..) ..... parse() is executed. org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse() org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parseStatement(Method)

for (Method method : methods) {
        try {
          // issue #237
          if (!method.isBridge()) {
            parseStatement(method);
          }
        } catch (IncompleteElementException e) {
          configuration.addIncompleteMethod(new MethodResolver(this, method));
        }
      }

If there is an issue with parsing the statement (which occured in mycase as the statement had @ResultMap annotation, but resultMap wasn't provided to configuration.), the method is added in INCOMPLETE_METHODS in configuration which later raises the exception.

@Select("select role_id, role_name, allowed_actions::bigint, denied_actions::bigint from acm_role")
    @ResultMap("com.hemant.data.mapper.RoleMapper." + PermissionDBHook.ROLE_MAP)
    public List<Role> getAllRoles();

On adding resultMap to configuration before mapper, solved it

   Configuration configuration = new Configuration(environment);
   //Hemant - result map should be added before mappers
   configuration.addResultMap(getResultMapForRoles(configuration));
   configuration.addMappers("com.hemant.data.mapper");
like image 2
hemantvsn Avatar answered Oct 17 '22 03:10

hemantvsn