MyBatis=XMLのイメージの方も多いと思いますが、「アノテーション」と「任意のJavaクラスのメソッド」にSQLを記載することができます(つまりXML書かなくてもMyBatisを使ってDBアクセスすることができます)。あまり知られていないかもしれないですが、「任意のJavaクラスのメソッド」を使用して動的SQLを記載すると、カバレッジ測定ツールと連動してSQLの生成ロジックに対するテストの充足性を確認することもできちゃいます。
JavaコードにSQLを記載したMapper
以下は、静的SQLを「アノテーション」に、動的SQLを「メソッド」に記載するしたMapperインタフェースになります。
package com.example.demo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Objects;
// language=sql
@Mapper
public interface PersonMapper {
// アノテーションにSQLを指定する
@Select("""
SELECT
id
,name
,address
,age
,memo
FROM
person
WHERE
id = #{id}
""")
Person selectOne(int id);
// 任意のクラスのメソッドにSQLを指定する
// language=sql
class SelectByCriteriaSqlProvider {
public static StringBuilder provideSql(PersonCriteria criteria) {
StringBuilder sb = new StringBuilder("""
SELECT
id
,name
,address
,age
,memo
FROM
person
WHERE 1 = 1
""");
if (StringUtils.hasLength(criteria.name)) {
sb.append("""
AND name = #{name}
""");
}
if (StringUtils.hasLength(criteria.address)) {
sb.append("""
AND address = #{address}
""");
}
if (Objects.nonNull(criteria.age)) {
sb.append("""
AND age = #{age}
""");
}
return sb;
}
}
@SelectProvider(SelectByCriteriaSqlProvider.class) // メソッド名をprovideSqlするとmethod属性は省略できる
List<Person> selectByCriteria(PersonCriteria criteria);
}
カバレッジの確認
ageに条件を指定したテストのみ実行した時のカバレッジはこんな感じになります。nameとaddressを指定したテストが不足していることがわかります!!
参考:Personクラス
package com.example.demo;
public record Person(int id, String name, String address, Integer age, String memo) {
}
参考:PersonCriteriaクラス
package com.example.demo;
public class PersonCriteria {
public String name;
public String address;
public Integer age;
}
まとめ
複雑なマッピングを行おうとするとXMLでしかサポートしていないケースはありますが、自動マッピングとアノテーションを使ったマッピングでも多くのパターンをサポートできると思います。データベースへアクセスする処理を分散させたくない場合やSQLの生成ロジックのカバレッジを取得したい場合は、JavaコードにSQLを記載する方法の採用を検討してみると良いと思います。