7
votes

Is there a way to run Flyway Java-based callbacks with Spring boot? I'm converting an existing project that after each migration updates some view definitions, and this is done by Java as it needs some extra logic. I know it could be done in pl/pgsql (we are using Postgres) but it is already done and tested in Java.

Spring boot docs says it is possible, but it is listed that the callback scripts should live in same dir as migrations, maybe this works just for SQL based callbacks.

This code works without Spring Boot:

    Flyway flyway = new Flyway();
    flyway.setDataSource(this.getDataSource());
    flyway.setLocations("/db/migration");
    flyway.setCallbacks(new LogMaintenanceFlywayCallback());
    flyway.migrate();

I have several migrations in /db/migration and after each one I need to execute my callback. It works in my current project and I need to do the same (or another way to get the same behavior) in Spring Boot.

5
It works. You need to put your Java classes in the db.migrations package. - Wim Deblauwe
Do they have to be named in a standard? I had created a SomeMaintenanceFlywayCallback, implementing interface FlywayCallback and method afterEachMigrate does not get called. I have tried to rename the class to AfterEachMigrate, but no success too. It is in db.migrations package, side by side with a Java migration that is executed, so the build path is ok. - Fernando M. Pinheiro
SQL migrations should be in src/main/resources/db/migration. Java migrations should be in src/main/java/db/migration. Each file normally starts with Vxxx__some-text-here.sql or Vxxx__MyJavaClass.java`. - Wim Deblauwe
Just saw my first comment was wrong. It is NOT db.migrations, but db.migration. See docs.spring.io/spring-boot/docs/current/reference/html/… - Wim Deblauwe
I wrote it wrong too, it is already in db.migration. As I said, my migrations are being executed, what I need is the callback, after each migration run some code. I have updated my question to include the manual way to use Flyway. - Fernando M. Pinheiro

5 Answers

4
votes

You can have a configuration like this and it will work:

@Configuration
public class FlywayFactory {

    @Bean
    public FlywayMigrationInitializer flywayInitializer(Flyway flyway, FlywayCallback flywayCallback) {
        flyway.setCallbacks(flywayCallback);
        return new FlywayMigrationInitializer(flyway);
    }

    @Bean
    public FlywayCallback flywayCallback() {
        return new LogMaintenanceFlywayCallback();
    }
}
2
votes

Since method setCallbacks(Callback... callbacks) of the Flyway has been deprecated and will be removed in Flyway 6.0, you can use new API and FlywayConfigurationCustomizer to set up custom Java-based callbacks. Then the configuration is as below:

@Configuration
public class FlywayFactory {

    @Bean
    public FlywayConfigurationCustomizer flywayConfigurationCustomizer() {
        return configuration -> configuration.callbacks(new LogMaintenanceFlywayCallback());
    }
}
2
votes

There seems to be no possibility to set the callbacks in the Spring Boot autoconfiguration (See FlywayAutoConfiguration.java)

There are 2 things you can do:

  1. Create your own Flyway instance in one of your Configuration classes. Spring Boot will not create his instance in case you do that.
  2. Autowire the Flyway instance in one of your Configuration classes and call the setCallbacks method in a PostConstruct method (But it might be tricky to make sure you call the setter before the migration starts)
1
votes

You can override the Flyway migration stragtey

@Component
public class CallbackFlywayMigrationStrategy implements FlywayMigrationStrategy {

    @Override
    public void migrate(Flyway flyway) {
        flyway.setCallbacks(new LogMaintenanceFlywayCallback());
        flyway.migrate();
    }

}
0
votes

You can define a bean of type org.flywaydb.core.api.callback.Callback as follows:

@Bean
public Callback logMaintenanceFlywayCallback() {
    return new LogMaintenanceFlywayCallback();
}