Chris Sim
Chris Sim

Reputation: 4132

Add xml mapper to the configuration of myBatis in the java code with path different than the interface one

I initialized my SqlSessionFactory in java code using an environment and datasource defined within the java code as below:

TransactionFactory trxFactory = new JdbcTransactionFactory();
Environment env = new Environment("development", trxFactory, dataSource);
Configuration config = new Configuration(env);
config.setJdbcTypeForNull(JdbcType.NULL);
TypeAliasRegistry aliases = config.getTypeAliasRegistry();
aliases.registerAlias("XXXAttempt", XXXAttemptDao.class);
config.addMapper(XXXAttemptMapper.class);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);

my problem is that I need to add my xml mappers here but I couldn't: I tried to use:

config.addMappers("config/mybatis/xxx/*.xml");

and

config.addMappers("config/mybatis/xxx/*.xml");

with no luck. note that config.addMapper accepts only java class

The only way that worked is to move the xml file to the same package like the interface example to (REFERENCE):

config/com/example/mappers/XXXAttemptMapper.xml

but what I need is to be consistent with other projects and put the xml file in the below path:

config/myBatis/myDb/XXXAttemptMapper.xml

how to add the path for my xml file in the above location?

Upvotes: 2

Views: 2344

Answers (2)

bayisehat
bayisehat

Reputation: 1

MyBatis-spring supports mapper interface and mapper xml have different name. In this example, mapper interface IMapper.java is in package com.example.myproject and mapper xml is in resources/mapper/mapper.xml. An option is to use the mapperLocations property of the factory bean.

private DataSource dataSource(String driver, String url, String userName, String password) {
    return new PooledDataSource(driver, url, userName, password);
}

public SqlSessionFactory createSqlSessionFactory(String driver, String url, String userName, String password) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setTransactionFactory(new JdbcTransactionFactory());
    factoryBean.setDataSource(dataSource(driver, url, userName, password));
    factoryBean.setMapperLocations(
            new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml")
    );

    return factoryBean.getObject();
}

Notice the method setMapperLocations accepts Resource as a parameter, and here the path (using pattern) is mapper/*.xml. You can using mapper interface like this:

 try (SqlSession session = sqlSessionFactory.openSession()) {
        IMapper mapper = session.getMapper(IMapper.class);
        //execute query here
    }

Upvotes: 0

This is not provided out of the box in mybatis. The actual relation between mapper interface and mapper xml file is hardcoded in MapperAnnotationBuilder class:

String xmlResource = type.getName().replace('.', '/') + ".xml";

And there is no built-in way to override this. In order to change this you need to implement your own equivalent of the MapperAnnotationBuilder (you can inherit most of its functionality but would need to override parse method in order to change call the method that would replace loadXmlResource):

class MyMapperAnnotationBuilder extends MapperAnnotationBuilder {
  public void parse() {
    String resource = type.toString();
    if (!configuration.isResourceLoaded(resource)) {
      loadXmlResourceFromCustomPlace();
      // ... continue as MapperAnnotationBuilder.parse method
    }
  }
  void private loadXmlResourceFromCustomPlace() {
    // this should be similar to MapperAnnotationBuilder.loadXmlResource
    // but load resource from some other place
  }
}

Now you need to make use of MyMapperAnnotationBuilder in your own implementation of the class similar to org.apache.ibatis.binding.MapperRegistry (let's say you call it MyMapperRegister). You need to inherit from it and override addMapper(Class<T> type) method to use MyMapperAnnotationBuilder.

And the final step is to use your mapper registry implementation in the Configuration. There is no way to set it externally so you would need to inherit from Configuration and use you mapper registry:

class MyConfiguration extends Configuration {
  public MyConfiguration{Environment environment) {
    super(environment);
    this.mapperRegistry = new MyMapperRegister(this);
  }

After this you use MyConfiguration the same way you use Configuration to configure mybatis and it will load xml mappers from the place defined by the logic implemented in MyMapperAnnotationBuilder.loadXmlResourceFromCustomPlace.

Upvotes: 2

Related Questions