spring-projects/spring-boot

Flyway Java migration not supported in native images

bclozel opened this issue · 6 comments

As discussed on gitter with @jnizet :

Hi team. I was just experimenting with native image support with a small application I have, and I think I found a missing piece in the native support. Flyway migrations are correctly detected and run... except the Java migrations. I get the following warning from Flyway at startup:

WARN 1 --- [ main] o.f.core.internal.command.DbMigrate : Schema "public" has a version (011) that is newer than the latest available migration (010) !

And the reason is that the migration 011, which has been run by a previous run of the application (in "non-native" mode), is a Java migration rather than a more traditional SQL migration (https://flywaydb.org/documentation/tutorials/java)

While we support the discovery of static sql migration files at runtime in a native image (using a custom resolver, org.springframework.boot.autoconfigure.flyway.NativeImageResourceProviderCustomizer) we are currently missing reflection metadata entries for the Java migration classes, since they are instantiated reflectively.

I'm not 100% sure that it's enough to register hints for the migration classes. Flyway somehow needs to find them, and classpath scanning in native-image doesn't work like it does on the JVM. We might need to find them at AOT build time and then help flyway find them later in the native image.

You can work around this issue by declaring a bean of type FlywayConfigurationCustomizer and register your Flyway Java migrations manually:

@Component
class JavaMigrationsFlywayCustomizer implements FlywayConfigurationCustomizer {

	@Override
	public void customize(FluentConfiguration configuration) {
		configuration.javaMigrations(new V1__create_table(), new ...);
	}

}

Another worker around according to docs is

import org.springframework.aot.hint.RuntimeHintsRegistrar;

public class MyRuntimeHints implements RuntimeHintsRegistrar {

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        // migration
        hints.resources().registerPattern("db/migration/V1__init_migration.sql");
    }

}

@SpringBootApplication
@ImportRuntimeHints(value = {MyRuntimeHints.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

This issue is about migrations written in Java. @emmanuelU17, your hint is for a script-based migration and should not be necessary as we already automatically register hints for db/migration/*:

static class FlywayAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerPattern("db/migration/*");
}
}

If that's not working for you please open a new issue with a minimal sample that reproduces the problem and we will take a look.

I don't think we should tackle this one. There's a fairly straightforward workaround (that I've added to the existing Flyway section in the wiki) and I think any further improvements in this area should be made in Flyway itself.