TL;DR
-
BeanPropertyRowMapper
/DataClassRowMapper
/SingleColumnRowMapper
はConversionService
を登録することで値の変換ができる1 - 何も指定していない状態でも、
DefaultConversionService.getSharedInstance()
の取得結果が利用されている
本文
SpringFramework
にはConversionService
を用いた型変換の仕組みがデフォルトで用意されており、RowMapper
の中でもそれを利用した型変換を行うことができます。
以下のように、数値で年月を表したカラムをjava.time.YearMonth
に変換して取得する場面を例にします。
CREATE TABLE IF NOT EXISTS `foo_table` (
`year_month` MEDIUMINT UNSIGNED NOT NULL,
PRIMARY KEY (`year_month`)
);
以下のように、何も設定せずに取得処理を行うとエラーが発生します。
SingleColumnRowMapper<YearMonth> mapper = new SingleColumnRowMapper<>(YearMonth.class);
// この取得処理でTypeMismatchDataAccessExceptionが発生する
YearMonth actual = template.queryForObject("SELECT year_month FROM foo_table", mapper);
ConversionService
を設定することで、この取得処理を行えるようにします。
今回はDefaultConversionService
にConverter
を設定し、更にそれをRowMapper
に登録することでこれを行う例を示します2。
SingleColumnRowMapper<YearMonth> mapper = new SingleColumnRowMapper<>(YearMonth.class);
// Converterの登録処理
DefaultConversionService defaultConversionService = new DefaultConversionService();
defaultConversionService.addConverter(new Converter<Integer, YearMonth>() {
@Override
public YearMonth convert(@NotNull Integer source) {
return YearMonth.of(source / 100, source % 100);
}
});
mapper.setConversionService(defaultConversionService);
YearMonth actual = template.queryForObject("SELECT year_month FROM foo_table", mapper);
assertEquals(YearMonth.of(2021, 1), actual);
補足: DefaultConversionServiceについて
Spring
全体で、ConversionService
を設定しなかった場合はDefaultConversionService.getSharedInstance()
で取得されるstatic
なConversionService
が利用されます。
このインスタンスにConverter
を設定すれば、デフォルトではアプリケーション全体でそれを使い回すことができます。
DefaultConversionService sharedInstance =
(DefaultConversionService) DefaultConversionService.getSharedInstance();
sharedInstance.addConverter(new Converter<Integer, YearMonth>() {
@Override
public YearMonth convert(@NotNull Integer source) {
return YearMonth.of(source / 100, source % 100);
}
});
また、SpringFramework
内でString
-> Enum
のような変換が行われるのはこのsharedInstance
の働きによるものです。
どのような変換が行われるかはソースコードから読み取ることができます。