LoginSignup
0
0

More than 3 years have passed since last update.

【SpringJdbc】ConversionServiceを用いてRowMapperによるマッピング時に値を変換する

Posted at

TL;DR

  • BeanPropertyRowMapper/DataClassRowMapper/SingleColumnRowMapperConversionServiceを登録することで値の変換ができる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を設定することで、この取得処理を行えるようにします。
今回はDefaultConversionServiceConverterを設定し、更にそれを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()で取得されるstaticConversionServiceが利用されます。

このインスタンスにConverterを設定すれば、デフォルトではアプリケーション全体でそれを使い回すことができます。

DefaultConversionServiceに設定する例
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の働きによるものです。
どのような変換が行われるかはソースコードから読み取ることができます。


  1. タイトルが長くなりすぎるため省きましたが、org.springframework.jdbc.coreに定義されたRowMapperでもConversionServiceを登録できないものが存在します。 

  2. ConverterFunctionalInterfaceであるためラムダでも書くことができますが、Generics関連の問題により自分の環境では実行時エラーになったため、例では匿名クラスを用いた書き方をしています。 

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0