Miss Kitty
Miss Kitty

Reputation: 182

Spring Boot MyBatis @MapperScan No Longer Functions as WAR

Description of Issue

I have a Spring Boot Java application which uses MyBatis Mappers that talk to DB2 through the use of interfaces with XML.

This set up works properly when running as a Spring Boot application in the Eclipse IDE. However, when I use Mavan to build the application as a WAR file, and deploy it on an external Tomcat server, suddenly I receive errors that my mappers cannot be found when the application deploys:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springmapper': Unsatisfied dependency expressed through field 'thingTypes'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'otherthingtypes': Invocation of init method failed; nested exception is 

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.myapplicaton.dao.MybatisMapper.selectByExample

I get the feeling that, when running as a WAR, the app is no longer scanning these MyBatis mappers as mappers. I must need to change some configuration, but I can't figure out what.

====================

Current Configuration (Works when running on Eclipse IDE as Spring Boot app)..

(1) All MyBatis java mappers in com.myapplicaton.dao have the @Mapper annotation:

package com.myapplicaton.dao;

@Mapper
public interface MybatisMapper {
   List<Thing> selectByExample(ThingExample example);
   //... 
}

(2) Added a MapperScan to the application startup..

@SpringBootApplication
@MapperScan({"com.myapplicaton.dao","com.myapplicaton.other.mappers"})
public class MyApplication extends SpringBootServletInitializer 
{

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

(3) Use the MyBatis Mappers in @Autowired classes:

@Configuration
public class SomeConfig {

    @Bean(name = "springmapper")
    @Scope(value = "singleton")
    public SpringMapper getSpringMapper() {
        return new SpringMapper();
    }

    @Bean(name = "thingTypes")
    @Scope(value = "singleton")
    public ThingTypes thingTypes() {
        return new ThingTypes();
    }
}
package com.myapplicaton.other.mappers;

public class SpringMapper {

    @Autowired
    ThingTypes thingTypes;

    //...
}
package com.myapplicaton.beans;

public class ThingTypes {
    @Autowired
    MybatisMapper mybatisMapper;

    //...
}

====================

Question

Why doesn't this work when deployed as a WAR?

Upvotes: 0

Views: 1273

Answers (1)

Miss Kitty
Miss Kitty

Reputation: 182

Alright, after messing with this all day, I sort of have an answer.

Firstly, I had to remove two 'problem' beans I had which used @PostConstruct on an init() method which used an @Autowired Mybatis mapper. I don't know why it didn't like that, but I don't care because after I removed them, the application booted properly as a WAR.. mostly.

It used to do something like this:

package com.myapplicaton.beans;

public class ThingTypes {
    @Autowired
    MybatisMapper mybatisMapper;

    @PostConstruct
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    private void init() {
          mybatisMapper.selectByExample(example);
    }
}

The second issue I had was that the application could not find the MyBatis mapper .xml files in my dao package when deployed as a WAR. It was fine when run on Eclipse, as per usual.

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.myapplicaton.dao.MybatisMapper.selectByExample

I checked the WAR file, and lo and behold, the .xml files had been skipped by Maven and only the Java class files lived in that folder. I couldn't figure out how to unskip .xml files with spring-boot-maven-plugin, and I wasn't about to try to figure out another plugin, so I was able to beat the system as follows:

I created a set of folders in the src/main/resources/ folder of the app with exactly the same folder structure as where the .java interface mappers were located. So, I created src/main/resources/com/myapplication/dao. I put all of the .xml files in there.

Upon checking the new WAR, the .xml files were placed into the same directory as the java class files, and MyBatis worked properly.

Hurrah.

Upvotes: 1

Related Questions