MyBatis with Annotation’s

The MyBatis configuration xml defines the connection info to the database and the mapper interfaces available to the database.

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <environments default="TestDB">

        <environment id="TestDB">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/"/>
                <property name="username" value="TestDBUser"/>
                <property name="password" value="TestDBPW"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper class="com.test.mapper.UserMapper"/>
        <mapper class="com.test.mapper.CompanyMapper"/>
    </mappers>

</configuration>

The Mapper class is an interface that contains the queries and sets the return type.

public interface UserMapper {

    final String ALL_USERS = "SELECT * FROM USER";
    final String USER_BY_SCREEN_NAME = ALL_USERS + " WHERE USER.screenname=#{screenName}";
    
    @Select(ALL_USERS)
    @Results(value = {
            @Result(property = "firstName",     column = "firstname"),
            @Result(property = "lastName",      column = "lastname"),
            @Result(property = "userName",      column = "screenname"),
            @Result(property = "emailAddress",  column = "emailaddress")
    })
    List<User> getUsers();

    @Select(USER_BY_SCREEN_NAME)
    @Results(value = {
            @Result(property = "firstName",     column = "firstname"),
            @Result(property = "lastName",      column = "lastname"),
            @Result(property = "userName",      column = "screenname"),
            @Result(property = "emailAddress",  column = "emailaddress")
    })
    User getUserByScreenName(String screenName);
}

To use the new mapper I usually will create a DatabaseBuilder class that uses generics to return the mapper for that database.

public class DatabaseBuilder {
    private final String conf;

    public DatabaseHelper(Database database) {
        this.conf = database.getEnvironment();
    }

    public <T> T getMapper(Class<T> mapperInterface) {
        try {
            Reader reader = Resources.getResourceAsReader(conf);

            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sessionFactory = builder.build(reader);
            SqlSession session = sessionFactory.openSession();

            return session.getMapper(mapperInterface);
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("Failed to return mapper");
    }

    public <T> T getMapper(Class<T> mapperInterface, String environment) {
        try {
            Reader reader = Resources.getResourceAsReader(conf);

            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sessionFactory = builder.build(reader, environment);
            SqlSession session = sessionFactory.openSession();

            return session.getMapper(mapperInterface);
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("Failed to return mapper");
    }

    public <T> T getMapper(Class<T> mapperInterface, Properties properties) {
        try {
            Reader reader = Resources.getResourceAsReader(conf);

            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sessionFactory = builder.build(reader, properties);
            SqlSession session = sessionFactory.openSession();

            return session.getMapper(mapperInterface);
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("Failed to return mapper");
    }

    public <T> T getMapper(Class<T> mapperInterface, String environment, Properties properties) {
        try {
            Reader reader = Resources.getResourceAsReader(conf);

            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sessionFactory = builder.build(reader, environment, properties);
            SqlSession session = sessionFactory.openSession();

            return session.getMapper(mapperInterface);
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("Failed to return mapper");
    }

    public enum Database {
        //The path to your MyBatis xml file
        TESTDB("test-db.conf.xml")
        // If you have more then one DB with custom mappers place them here!
        //TESTDB2("test_db2.conf.xml")

        private String config;

        private Database(String config) {
            this.config = config;
        }

        public String getEnvironment() {
            return this.config;
        }
    }
}

Now you can use your custom queries with the following

UserMapper userMapper = new DatabaseBuilder(Database.TESTDB).getMapper(UserMapper.class);
List<User> users = userMapper.getUsers();
User testUser = userMapper.getUserByScreenName("EpicTester");

Leave a comment