MyBatisのMapperをCDIに登録する方法

# やりたいこと
MyBatisのMapperをJakartaEEのCDIに登録したい。

# 課題
JakartaEEのCDIとOSSのMyBatisを併用する場合、Springのように@Mapperアノテーションを記述するだけではDIに登録できないらしいです。そのため、DIに登録するための記述を追加する必要があります。

# 前提
ビジネスロジック層はJakartaEEのCDI（4.1.0）、インテグレーション層はMyBatis（3.5.17）、ビルドツールはmavenを使用します。

# MapperをDIに登録する手順
①pom.xmlを修正する
②mybatis-config.xmlを作成する
③②で作成したmybatis-config.xmlを読み込んだSqlSessionをCDIに登録する
④ServiceクラスでSqlSessionをインジェクションする

流れとしては、mybatis-config.xmlにMapperを登録し、それを読み込んだSqlSessionをCDIに登録し、登録したSqlSessionをインジェクトすることでMapperを使うことができるという感じです。

# ①pom.xmlを修正する
pom.xmlにCDI-API、MyBatis、MyBatis-CDIを追加します。
（バージョンは適宜調整してください。）
```
		<!-- CDI API -->
		<dependency>
			<groupId>jakarta.enterprise</groupId>
			<artifactId>jakarta.enterprise.cdi-api</artifactId>
			<version>4.1.0</version>
		</dependency>

		<!-- MyBatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.17</version>
		</dependency>

		<!-- MyBatis-CDI -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-cdi</artifactId>
			<version>2.1.0</version>
		</dependency>
```

# ②mybatis-config.xmlを作成する
DBへの接続情報や、Mapperの情報を記載したmybatis-config.xmlを作成し、src/main/resources配下に配置します。
以下、mybatis-config.xmlの例でございます。
```
<?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>
    <!--DB接続先情報-->
	<environments default="test">
		<environment id="test">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="org.postgresql.Driver" />
				<property name="url" value="接続先URL" />
				<property name="username" value="ユーザー名" />
				<property name="password" value="パスワード" />
			</dataSource>
		</environment>
	</environments>

    <!--以下にMapper情報を登録-->
    <!--本例では、mybatis-config.xmlと同じディレクトリに配置したmapper.xmlを登録しています-->
	<mappers>
		<mapper resource="./mapper.xml" />
	</mappers>
</configuration>
```
以下のような記述で直接Mapperを登録することも可能です。
```
	<mappers>
		<mapper class="Mapperの相対パス" />
	</mappers>
```

# ③②で作成したmybatis-config.xmlを読み込んだSqlSessionをCDIに登録する
mybatis-config.xmlを読み込んだSqlSessionをCDIに登録することで、MapperもCDI経由で呼び出すことができるようになります。
方法としては、SqlSessionFactory型を戻り値とするメソッドを用意し、mybatis-config.xmlを読み込ませたうえでSqlSessionFactoryBuilderクラスを用いてSqlSessionFactoryを生成/returnすることでSqlSessionをCDIに登録します。
例）SqlSessionFactoryProducer.java
```
package com.example.util;

import java.io.IOException;
import java.io.InputStream;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Produces;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.mybatis.cdi.SessionFactoryProvider;

//@Dependentで本クラスをCDI登録
@Dependent
public class SqlSessionFactoryProducer {

    //@SessionFactoryProviderとして本メソッドを登録
	@Produces
	@ApplicationScoped
	@SessionFactoryProvider
    //SqlSessionFactoryを戻り値型に指定
	public SqlSessionFactory produceFactory() throws IOException{
        //mybatis-config.xmlを読み込んだInputStreamを生成
		InputStream fileStream = Resources.getResourceAsStream("mybatis-config.xml");
        //上記InputStreamを読み込んだSqlSessionFactoryBuilderを生成/returnすることで
        //SqlSessionをApplicationスコープでCDI登録
		return new SqlSessionFactoryBuilder().build(fileStream);
	}

}
```

# ④ServiceクラスでSqlSessionをインジェクションする
最後に、③で登録したSqlSessionをインジェクトしてMapperを取得/利用します。
```
    //SqlSessionをインジェクション
    @Inject
	private SqlSession sqlSession;

    //SqlSessionからMapperを取得するprivateメソッド
 	private SampleMapper sampleMapper() {
		return sqlSession.getMapper(SampleMapper.class);
	}

    //上記privateメソッドを用いてMapperを取得/利用
 	public List<SampleDto> getList(){
		 return sampleMapper().getList();
	}
```

# ソースコード
上記サンプルコードはGithubにコミットしています。

https://github.com/SatoHiroto526/JerseySample/tree/master

# 参考にさせていただいた記事

https://qiita.com/RyoTa63292153/items/3cb7a51aada0ec604636

https://rheb.hatenablog.com/entry/2024/11/22/180644