Injecting MyBatis beans

This section will take you through de details of the discovery and injection process.

Producing a Factory

The SqlSessionFactory is the source of any MyBatis bean so first you need to create one (at least) and let the container know about it existence. To do so, create a bean with producer method, and make sure that you add the @ApplicationScoped annotation to it because we just want to have one instance of the factory for the whole application.

In order to let the container identify the producers to be used, you must annotate them with @SessionFactoryProvider.

public class MyProducers {

  @Produces
  @ApplicationScoped
  @SessionFactoryProvider
  public SqlSessionFactory produceFactory() {
    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    return sqlSessionFactory;
  }

}

NOTE If you forget the @ApplicationScoped the factory will be created on each injection, what implies parsing and loading the whole MyBatis xml file set. Your application will not fail but it will be terribly slow.

NOTE If you forget the @SessionFactoryProvider the factory will be ignored by mybatis-cdi.

Disvovering and injecting Mappers

There is nothing special more than injecting the mapper as any other CDI dependecy:

public class FooService {

  @Inject UserMapper userMapper;

  public User doSomeStuff(String userId) {
    return this.userMapper.getUser(userId);
  }

}

Then it will get an instance (a proxy in fact) of that mapper from the SqlSessionFactory registered in the CDI container and inject it into the bean. This proxy is not a normal mapper but a thread safe singleton so you should not worry about its scope.

Any configuration problem that may happen during the initialization process will make the module throw a MyBatisCdiConfiurationException. Given that there is not much to configure, this exception is only thrown when the SqlSessionFactory cannot be found or is misconfigured.

Resolving ambiguities

In case you have more than one SqlSessionFactory you can choose the one you want to use in any injection point by using:

  • One or more qualifiers (defined by you)
  • The name of the SqlSessionFactory (qualified with @Named)
  • Any paranoid combination of both

Follows below an snippet that shows a producer that creates two SqlSessionFactorys. A qualifier is used to differentiate them as you would do with any other CDI bean:

@ApplicationScoped
@Produces
@FooQualifier
@SessionFactoryProvider
public SqlSessionFactory createManagerFoo() throws IOException {
  ...
}

@ApplicationScoped
@Produces
@BarQualifier
@SessionFactoryProvider
public SqlSessionFactory createManagerBar() throws IOException {
  ...
}

Now that there is no ambiguity you can select what factory you want to inject by adding the qualifier to it:

@Inject @FooQualifier UserMapper userMapper;

You can also give a name to your SqlSessionFactory:

@ApplicationScoped
@Produces
@Named("fooManager")
@SessionFactoryProvider
public SqlSessionFactory createManager() throws IOException {
  ...
}

And refer to it by its name in an injection point:

@Inject @Named("fooManager") UserMapper userMapper;

Injecting an SqlSession

You can inject a thread safe SqlSession by requesting its injection as follows:

@Inject SqlSession sqlSession;

The factory selection criteria we saw for mappers apply also to SqlSession injection.

NOTE MyBatis-CDI controls the lifecycle of the injected SqlSession so you must not call any transactional method like commit() or rollback(), nor any lifecycle method like close().