flywayのコールバックをJavaで書く


はじめに

Gradleとflywayを使ってデータベースマイグレーションをしているアプリで
コールバックをJavaで書いた時に試行錯誤しました。

結論からいうと、flywayのタスク実行前にCallbackクラスをコンパイルすれば良いです。

今回検証したコードは以下のリポジトリを参照してください。
https://github.com/mahaker/flyway-callback-java

環境

Java: OpenJDK 11
Gradle: 5.2.1
flyway: 6.4.2
Postgres: 12

コールバックをJavaで書く

org.flywaydb.core.api.callback.Callbackインターフェースを実装したクラスを作って
flyway.callbacksプロパティに完全修飾名を設定します。
https://flywaydb.org/documentation/api/hooks#java-based-callbacks

また、flywayのタスクより先にclassesタスクを実行するようにします。※これ大事
(正確にはcompileJavaタスクかな?)

FillTestData.java
package db.migration;

import java.sql.PreparedStatement;

import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.callback.Context;
import org.flywaydb.core.api.callback.Event;

public class FillTestData implements Callback {

    @Override
    public boolean supports(Event event, Context context) {
        return Event.AFTER_MIGRATE.equals(event);
    }

    @Override
    public boolean canHandleInTransaction(Event event, Context context) {
        return false;
    }

    @Override
    public void handle(Event event, Context context) {
        try (
            final PreparedStatement statement = context
                .getConnection()
                .prepareStatement("INSERT INTO PERSON(ID, NAME, AGE) VALUES (1, 'userA', 20), (2, 'userB', 22)")
        ) {
            statement.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
build.gradle
// 必要なものだけ抜粋
plugins {
    id "org.flywaydb.flyway" version "6.4.2"
}

group 'org.example'
version '1.0-SNAPSHOT'

sourceCompatibility = 11

flyway {
    url = 'jdbc:postgresql://localhost:15432/exampledb'
    user = 'postgres'
    password = 'example'
    locations = [ 'filesystem:./src/main/resources/db/migration/' ]
    callbacks = [ 'db.migration.FillTestData' ]
}

// !!大事!!
flywayClean.dependsOn(classes)
flywayMigrate.dependsOn(classes)

まとめ

マイグレーションを実行するとinsert文が実行されていることが確認できます。

この方法はflywayの中の人に教えていただいたものです。
https://github.com/flyway/flyway/issues/2829