Restore compatibility with Flyway 5.2

Previously, the upgrade to Flyway 6 broke compatibility with Flyway
5.2 due to the use of method references that refer to two methods
that do not exist in Flyway 5.2.

This commit replaces the method references with lambdas that are only
called if the user sets the related property. Unless a new-in-Flyway-6
property is set, the auto-configuration will work as before. When such
a property is set the auto-configuration will fail with a
NoSuchMethodError. This approach was chosen to make the
incompatibility clear.

We have also introduced support for passing any JavaMigration beans
in the context into Flyway. This too relies on API that is new in
Flyway 6. It is possible (although unlikely) that users had
JavaMigration beans in Spring Boot 2.1 that were being ignored. This
commit restores this behaviour when using Flyway 5.2.

Closes gh-18193
pull/18151/head
Andy Wilkinson 5 years ago
parent b5589f8abe
commit b9bb84236b

@ -168,7 +168,8 @@ public class FlywayAutoConfiguration {
map.from(properties.getConnectRetries()).to(configuration::connectRetries); map.from(properties.getConnectRetries()).to(configuration::connectRetries);
map.from(properties.getSchemas()).as(StringUtils::toStringArray).to(configuration::schemas); map.from(properties.getSchemas()).as(StringUtils::toStringArray).to(configuration::schemas);
map.from(properties.getTable()).to(configuration::table); map.from(properties.getTable()).to(configuration::table);
map.from(properties.getTablespace()).to(configuration::tablespace); // No method reference for compatibility with Flyway 5.x
map.from(properties.getTablespace()).whenNonNull().to((tablespace) -> configuration.tablespace(tablespace));
map.from(properties.getBaselineDescription()).to(configuration::baselineDescription); map.from(properties.getBaselineDescription()).to(configuration::baselineDescription);
map.from(properties.getBaselineVersion()).to(configuration::baselineVersion); map.from(properties.getBaselineVersion()).to(configuration::baselineVersion);
map.from(properties.getInstalledBy()).to(configuration::installedBy); map.from(properties.getInstalledBy()).to(configuration::installedBy);
@ -201,7 +202,9 @@ public class FlywayAutoConfiguration {
map.from(properties.getErrorOverrides()).whenNonNull().to(configuration::errorOverrides); map.from(properties.getErrorOverrides()).whenNonNull().to(configuration::errorOverrides);
map.from(properties.getLicenseKey()).whenNonNull().to(configuration::licenseKey); map.from(properties.getLicenseKey()).whenNonNull().to(configuration::licenseKey);
map.from(properties.getOracleSqlplus()).whenNonNull().to(configuration::oracleSqlplus); map.from(properties.getOracleSqlplus()).whenNonNull().to(configuration::oracleSqlplus);
map.from(properties.getOracleSqlplusWarn()).whenNonNull().to(configuration::oracleSqlplusWarn); // No method reference for compatibility with Flyway 5.x
map.from(properties.getOracleSqlplusWarn()).whenNonNull()
.to((oracleSqlplusWarn) -> configuration.oracleSqlplusWarn(oracleSqlplusWarn));
map.from(properties.getStream()).whenNonNull().to(configuration::stream); map.from(properties.getStream()).whenNonNull().to(configuration::stream);
map.from(properties.getUndoSqlMigrationPrefix()).whenNonNull().to(configuration::undoSqlMigrationPrefix); map.from(properties.getUndoSqlMigrationPrefix()).whenNonNull().to(configuration::undoSqlMigrationPrefix);
} }
@ -220,8 +223,13 @@ public class FlywayAutoConfiguration {
private void configureJavaMigrations(FluentConfiguration flyway, List<JavaMigration> migrations) { private void configureJavaMigrations(FluentConfiguration flyway, List<JavaMigration> migrations) {
if (!migrations.isEmpty()) { if (!migrations.isEmpty()) {
try {
flyway.javaMigrations(migrations.toArray(new JavaMigration[0])); flyway.javaMigrations(migrations.toArray(new JavaMigration[0]));
} }
catch (NoSuchMethodError ex) {
// Flyway 5.x
}
}
} }
private String getProperty(Supplier<String> property, Supplier<String> defaultValue) { private String getProperty(Supplier<String> property, Supplier<String> defaultValue) {

@ -0,0 +1,121 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.flyway;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.Location;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.migration.JavaMigration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link FlywayAutoConfiguration} with Flyway 5.x.
*
* @author Andy Wilkinson
*/
@ClassPathOverrides("org.flywaydb:flyway-core:5.2.4")
class Flyway5xAutoConfigurationTests {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))
.withPropertyValues("spring.datasource.generate-unique-name=true");
@Test
void defaultFlyway() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Flyway.class);
Flyway flyway = context.getBean(Flyway.class);
assertThat(flyway.getConfiguration().getLocations())
.containsExactly(new Location("classpath:db/migration"));
});
}
@Test
void flywayJavaMigrationsAreIgnored() {
this.contextRunner
.withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayJavaMigrationsConfiguration.class)
.run((context) -> assertThat(context).hasNotFailed());
}
@Configuration(proxyBeanMethods = false)
static class FlywayJavaMigrationsConfiguration {
@Bean
TestMigration migration1() {
return new TestMigration("2", "M1");
}
@Bean
TestMigration migration2() {
return new TestMigration("3", "M2");
}
}
private static final class TestMigration implements JavaMigration {
private final MigrationVersion version;
private final String description;
private TestMigration(String version, String description) {
this.version = MigrationVersion.fromVersion(version);
this.description = description;
}
@Override
public MigrationVersion getVersion() {
return this.version;
}
@Override
public String getDescription() {
return this.description;
}
@Override
public Integer getChecksum() {
return 1;
}
@Override
public boolean isUndo() {
return false;
}
@Override
public boolean canExecuteInTransaction() {
return true;
}
@Override
public void migrate(org.flywaydb.core.api.migration.Context context) {
}
}
}
Loading…
Cancel
Save