title: MyBatis-Spring + @Configuration - Can't autowire mapper beans
body: <p>I have been trying to create a Spring project that uses MyBatis for the data access layer as a proof of concept for my team. I really want to avoid XML configuration if at all possible, so I'm attempting to wire everything together using annotated <strong>@Configuration</strong> classes.</p>
  
  <p>Everything <em>seems</em> to be wired correctly, but my mapper beans are not being AutoWired into my service layer.</p>
  
  <p>In my example I'm trying to wire together a UserDao, User entity, and a UserService.</p>
  
  <h2><strong>UserDao</strong></h2>
  
  <pre><code>public interface UserDao {
      @Select("SELECT * FROM users WHERE id = #{userId}")
      User get(@Param("userId") Integer userId);
  }
  </code></pre>
  
  <h2><strong>User</strong></h2>
  
  <pre><code>@Component("User")
  public class User implements Entity {
      public Integer userId;
      public String username;
  
      /** ... getters/setters ommitted **/
  }
  </code></pre>
  
  <h2><strong>UserServiceImpl</strong></h2>
  
  <pre><code>@Service("UserService")
  public class UserServiceImpl {
      private UserDao userDao = null;  
  
      public User getUserDetails(Integer userId) {
          return userDao.get(userId);        
      }
  
      @Autowired
      public void setUserDao(UserDao userDao) {
          this.userDao = userDao;
      }
  }
  </code></pre>
  
  <p>I'm wiring these together using two configuration classes.</p>
  
  <h2><strong>ApplicationContextConfig</strong></h2>
  
  <pre><code>@Configuration
  @EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
  @Import(DefaultDataAccessConfig.class) // I'm importing this because I thought ordering might be important, otherwise I was hoping to just let the component scanning pull in additional configuration files
  @ComponentScan(basePackages="com.example.gwtspringpoc.server",
                 excludeFilters=@Filter(type=FilterType.ANNOTATION,
                                        value=Controller.class))
  public class ApplicationContextConfig {
      /** No bean definitions needed here **/
  }
  </code></pre>
  
  <h2><strong>DefaultDataAccessConfig</strong></h2>
  
  <pre><code>@Configuration
  @EnableTransactionManagement
  public class DefaultDataAccessConfig implements TransactionManagementConfigurer {    
      @Bean
      public DataSource dataSource() {
          OracleDataSource ods = null;
          try {
              ods = new OracleDataSource();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
  
          ods.setURL("jdbc:oracle:thin:@//localhost:9601/sid");
          ods.setUser("user");
          ods.setPassword("pass");        
  
          return ods;       
      }
  
      @Override
      @Bean(name="transactionManager")
      public PlatformTransactionManager annotationDrivenTransactionManager() {
          return new DataSourceTransactionManager(dataSource());
      }
  
      @Bean
      public SqlSessionFactory sqlSessionFactory() {
          SqlSessionFactoryBean sf = new SqlSessionFactoryBean();        
          sf.setDataSource(dataSource());    
          try {
              return (SqlSessionFactory) sf.getObject();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      @Bean
      public SqlSession sqlSessionTemplate() {
          return new SqlSessionTemplate(sqlSessionFactory());
      }    
  
      /*
       * This did not work at all. It seems to be configured correctly, but the UserDao bean never
       * got created at any stage, which was very disappointing as I was hoping not to have to
       * create a bean definition for each DAO manually
       */
      /*@Bean
      public static MapperScannerConfigurer mapperScannerConfig() {
          MapperScannerConfigurer msc = new MapperScannerConfigurer();
          msc.setBasePackage("com.ca.spna.gwtspringpoc.server.model.dao");      
          msc.setAnnotationClass(Repository.class);      
  
          return msc;
      }*/
  
      /*
       * Because the above code did not work, I decided to create the mapping manually.
       * This is most likely my problem - something about this setup. My understanding
       * is that the MapperFactoryBean once instantiated by Spring, will create a proxy
       * object of type UserDao with the name "userDao" that can be injected elsewhere.
       */
      @Bean
      public MapperFactoryBean&lt;UserDao&gt; userDao() {
          MapperFactoryBean&lt;UserDao&gt; mfb = new MapperFactoryBean&lt;UserDao&gt;();        
          mfb.setMapperInterface(UserDao.class);
          return mfb;
      }
  }
  </code></pre>
  
  <p>You can read the comments above the last two methods in the above code snippet to gain more insight into how I'm creating the UserDao bean.</p>
  
  <p>Once I got all the configuration setup, I created a unit test to try to test the <strong>UserService</strong> using the <strong>AnnotationConfigContextLoader</strong>, but was immediately hit with the following exception when trying to run the test:</p>
  
  <h2><strong>Exception</strong></h2>
  
  <pre><code>Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.example.gwtspringpoc.server.service.UserServiceImpl.setUserDao(com.example.gwtspringpoc.server.model.dao.UserDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.gwtspringpoc.server.model.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
  </code></pre>
  
  <p>After seeing that, I commented out the <strong>@Autowired</strong> in the <strong>UserService</strong> and went back to my unit test and injected the <strong>ApplicationContext</strong> so I could inspect it, and the bean named "userDao" is in fact a <strong>MapperProxy</strong> instance.</p>
  
  <p>So, is my understanding of how the <strong>MapperFactoryBean</strong> works off track or is it just not very compatible with annotation driven configuration? Additionally, if anyone has any idea how to make the <strong>MapperScannerConfigurer</strong> work correctly, I would appreciate it greatly!</p>