diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index 046cd91f6086..a9c4c49aa288 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -193,87 +193,123 @@ private void applyConnectionDetails(FlywayConnectionDetails connectionDetails, D } } + /** + * Configure the given {@code configuration} using the given {@code properties}. + *
+ * To maximize forwards- and backwards-compatibility method references are not + * used. + * @param configuration the configuration + * @param properties the properties + */ private void configureProperties(FluentConfiguration configuration, FlywayProperties properties) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); String[] locations = new LocationResolver(configuration.getDataSource()) .resolveLocations(properties.getLocations()) .toArray(new String[0]); - map.from(properties.isFailOnMissingLocations()).to(configuration::failOnMissingLocations); - map.from(locations).to(configuration::locations); - map.from(properties.getEncoding()).to(configuration::encoding); - map.from(properties.getConnectRetries()).to(configuration::connectRetries); + configuration.locations(locations); + map.from(properties.isFailOnMissingLocations()) + .to((failOnMissingLocations) -> configuration.failOnMissingLocations(failOnMissingLocations)); + map.from(properties.getEncoding()).to((encoding) -> configuration.encoding(encoding)); + map.from(properties.getConnectRetries()) + .to((connectRetries) -> configuration.connectRetries(connectRetries)); map.from(properties.getConnectRetriesInterval()) .as(Duration::getSeconds) .as(Long::intValue) - .to(configuration::connectRetriesInterval); - map.from(properties.getLockRetryCount()).to(configuration::lockRetryCount); - map.from(properties.getDefaultSchema()).to(configuration::defaultSchema); - map.from(properties.getSchemas()).as(StringUtils::toStringArray).to(configuration::schemas); - map.from(properties.isCreateSchemas()).to(configuration::createSchemas); - map.from(properties.getTable()).to(configuration::table); - map.from(properties.getTablespace()).to(configuration::tablespace); - map.from(properties.getBaselineDescription()).to(configuration::baselineDescription); - map.from(properties.getBaselineVersion()).to(configuration::baselineVersion); - map.from(properties.getInstalledBy()).to(configuration::installedBy); - map.from(properties.getPlaceholders()).to(configuration::placeholders); - map.from(properties.getPlaceholderPrefix()).to(configuration::placeholderPrefix); - map.from(properties.getPlaceholderSuffix()).to(configuration::placeholderSuffix); - map.from(properties.getPlaceholderSeparator()).to(configuration::placeholderSeparator); - map.from(properties.isPlaceholderReplacement()).to(configuration::placeholderReplacement); - map.from(properties.getSqlMigrationPrefix()).to(configuration::sqlMigrationPrefix); + .to((connectRetriesInterval) -> configuration.connectRetriesInterval(connectRetriesInterval)); + map.from(properties.getLockRetryCount()) + .to((lockRetryCount) -> configuration.lockRetryCount(lockRetryCount)); + map.from(properties.getDefaultSchema()).to((schema) -> configuration.defaultSchema(schema)); + map.from(properties.getSchemas()) + .as(StringUtils::toStringArray) + .to((schemas) -> configuration.schemas(schemas)); + map.from(properties.isCreateSchemas()).to((createSchemas) -> configuration.createSchemas(createSchemas)); + map.from(properties.getTable()).to((table) -> configuration.table(table)); + map.from(properties.getTablespace()).to((tablespace) -> configuration.tablespace(tablespace)); + map.from(properties.getBaselineDescription()) + .to((baselineDescription) -> configuration.baselineDescription(baselineDescription)); + map.from(properties.getBaselineVersion()) + .to((baselineVersion) -> configuration.baselineVersion(baselineVersion)); + map.from(properties.getInstalledBy()).to((installedBy) -> configuration.installedBy(installedBy)); + map.from(properties.getPlaceholders()).to((placeholders) -> configuration.placeholders(placeholders)); + map.from(properties.getPlaceholderPrefix()) + .to((placeholderPrefix) -> configuration.placeholderPrefix(placeholderPrefix)); + map.from(properties.getPlaceholderSuffix()) + .to((placeholderSuffix) -> configuration.placeholderSuffix(placeholderSuffix)); + map.from(properties.getPlaceholderSeparator()) + .to((placeHolderSeparator) -> configuration.placeholderSeparator(placeHolderSeparator)); + map.from(properties.isPlaceholderReplacement()) + .to((placeholderReplacement) -> configuration.placeholderReplacement(placeholderReplacement)); + map.from(properties.getSqlMigrationPrefix()) + .to((sqlMigrationPrefix) -> configuration.sqlMigrationPrefix(sqlMigrationPrefix)); map.from(properties.getSqlMigrationSuffixes()) .as(StringUtils::toStringArray) - .to(configuration::sqlMigrationSuffixes); - map.from(properties.getSqlMigrationSeparator()).to(configuration::sqlMigrationSeparator); - map.from(properties.getRepeatableSqlMigrationPrefix()).to(configuration::repeatableSqlMigrationPrefix); - map.from(properties.getTarget()).to(configuration::target); - map.from(properties.isBaselineOnMigrate()).to(configuration::baselineOnMigrate); - map.from(properties.isCleanDisabled()).to(configuration::cleanDisabled); - map.from(properties.isCleanOnValidationError()).to(configuration::cleanOnValidationError); - map.from(properties.isGroup()).to(configuration::group); - map.from(properties.isMixed()).to(configuration::mixed); - map.from(properties.isOutOfOrder()).to(configuration::outOfOrder); - map.from(properties.isSkipDefaultCallbacks()).to(configuration::skipDefaultCallbacks); - map.from(properties.isSkipDefaultResolvers()).to(configuration::skipDefaultResolvers); - map.from(properties.isValidateMigrationNaming()).to(configuration::validateMigrationNaming); - map.from(properties.isValidateOnMigrate()).to(configuration::validateOnMigrate); + .to((sqlMigrationSuffixes) -> configuration.sqlMigrationSuffixes(sqlMigrationSuffixes)); + map.from(properties.getSqlMigrationSeparator()) + .to((sqlMigrationSeparator) -> configuration.sqlMigrationSeparator(sqlMigrationSeparator)); + map.from(properties.getRepeatableSqlMigrationPrefix()) + .to((repeatableSqlMigrationPrefix) -> configuration + .repeatableSqlMigrationPrefix(repeatableSqlMigrationPrefix)); + map.from(properties.getTarget()).to((target) -> configuration.target(target)); + map.from(properties.isBaselineOnMigrate()) + .to((baselineOnMigrate) -> configuration.baselineOnMigrate(baselineOnMigrate)); + map.from(properties.isCleanDisabled()).to((cleanDisabled) -> configuration.cleanDisabled(cleanDisabled)); + map.from(properties.isCleanOnValidationError()) + .to((cleanOnValidationError) -> configuration.cleanOnValidationError(cleanOnValidationError)); + map.from(properties.isGroup()).to((group) -> configuration.group(group)); + map.from(properties.isMixed()).to((mixed) -> configuration.mixed(mixed)); + map.from(properties.isOutOfOrder()).to((outOfOrder) -> configuration.outOfOrder(outOfOrder)); + map.from(properties.isSkipDefaultCallbacks()) + .to((skipDefaultCallbacks) -> configuration.skipDefaultCallbacks(skipDefaultCallbacks)); + map.from(properties.isSkipDefaultResolvers()) + .to((skipDefaultResolvers) -> configuration.skipDefaultResolvers(skipDefaultResolvers)); + map.from(properties.isValidateMigrationNaming()) + .to((validateMigrationNaming) -> configuration.validateMigrationNaming(validateMigrationNaming)); + map.from(properties.isValidateOnMigrate()) + .to((validateOnMigrate) -> configuration.validateOnMigrate(validateOnMigrate)); map.from(properties.getInitSqls()) .whenNot(CollectionUtils::isEmpty) .as((initSqls) -> StringUtils.collectionToDelimitedString(initSqls, "\n")) - .to(configuration::initSql); + .to((initSql) -> configuration.initSql(initSql)); map.from(properties.getScriptPlaceholderPrefix()) .to((prefix) -> configuration.scriptPlaceholderPrefix(prefix)); map.from(properties.getScriptPlaceholderSuffix()) .to((suffix) -> configuration.scriptPlaceholderSuffix(suffix)); configureExecuteInTransaction(configuration, properties, map); - map.from(properties::getLoggers).to(configuration::loggers); + map.from(properties::getLoggers).to((loggers) -> configuration.loggers(loggers)); // Flyway Teams properties - map.from(properties.getBatch()).to(configuration::batch); - map.from(properties.getDryRunOutput()).to(configuration::dryRunOutput); - map.from(properties.getErrorOverrides()).to(configuration::errorOverrides); - map.from(properties.getLicenseKey()).to(configuration::licenseKey); - // No method references for Oracle props for compatibility with Flyway 9.20+ + map.from(properties.getBatch()).to((batch) -> configuration.batch(batch)); + map.from(properties.getDryRunOutput()).to((dryRunOutput) -> configuration.dryRunOutput(dryRunOutput)); + map.from(properties.getErrorOverrides()) + .to((errorOverrides) -> configuration.errorOverrides(errorOverrides)); + map.from(properties.getLicenseKey()).to((licenseKey) -> configuration.licenseKey(licenseKey)); map.from(properties.getOracleSqlplus()).to((oracleSqlplus) -> configuration.oracleSqlplus(oracleSqlplus)); map.from(properties.getOracleSqlplusWarn()) .to((oracleSqlplusWarn) -> configuration.oracleSqlplusWarn(oracleSqlplusWarn)); map.from(properties.getOracleKerberosCacheFile()) .to((oracleKerberosCacheFile) -> configuration.oracleKerberosCacheFile(oracleKerberosCacheFile)); - map.from(properties.getStream()).to(configuration::stream); - map.from(properties.getUndoSqlMigrationPrefix()).to(configuration::undoSqlMigrationPrefix); - map.from(properties.getCherryPick()).to(configuration::cherryPick); - map.from(properties.getJdbcProperties()).whenNot(Map::isEmpty).to(configuration::jdbcProperties); - map.from(properties.getKerberosConfigFile()).to(configuration::kerberosConfigFile); - map.from(properties.getOutputQueryResults()).to(configuration::outputQueryResults); + map.from(properties.getStream()).to((stream) -> configuration.stream(stream)); + map.from(properties.getUndoSqlMigrationPrefix()) + .to((undoSqlMigrationPrefix) -> configuration.undoSqlMigrationPrefix(undoSqlMigrationPrefix)); + map.from(properties.getCherryPick()).to((cherryPick) -> configuration.cherryPick(cherryPick)); + map.from(properties.getJdbcProperties()) + .whenNot(Map::isEmpty) + .to((jdbcProperties) -> configuration.jdbcProperties(jdbcProperties)); + map.from(properties.getKerberosConfigFile()) + .to((configFile) -> configuration.kerberosConfigFile(configFile)); + map.from(properties.getOutputQueryResults()) + .to((outputQueryResults) -> configuration.outputQueryResults(outputQueryResults)); map.from(properties.getSqlServerKerberosLoginFile()) .whenNonNull() .to((sqlServerKerberosLoginFile) -> configureSqlServerKerberosLoginFile(configuration, sqlServerKerberosLoginFile)); - map.from(properties.getSkipExecutingMigrations()).to(configuration::skipExecutingMigrations); + map.from(properties.getSkipExecutingMigrations()) + .to((skipExecutingMigrations) -> configuration.skipExecutingMigrations(skipExecutingMigrations)); map.from(properties.getIgnoreMigrationPatterns()) .whenNot(List::isEmpty) - .as((patterns) -> patterns.toArray(new String[0])) - .to(configuration::ignoreMigrationPatterns); - map.from(properties.getDetectEncoding()).to(configuration::detectEncoding); + .to((ignoreMigrationPatterns) -> configuration + .ignoreMigrationPatterns(ignoreMigrationPatterns.toArray(new String[0]))); + map.from(properties.getDetectEncoding()) + .to((detectEncoding) -> configuration.detectEncoding(detectEncoding)); } private void configureExecuteInTransaction(FluentConfiguration configuration, FlywayProperties properties, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway10xAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway10xAutoConfigurationTests.java new file mode 100644 index 000000000000..e1e8ebdddbe3 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/Flyway10xAutoConfigurationTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2023 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.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; + +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.ClassPathExclusions; +import org.springframework.boot.testsupport.classpath.ClassPathOverrides; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link FlywayAutoConfiguration} with Flyway 10.x. + * + * @author Andy Wilkinson + */ +@ClassPathExclusions({ "flyway-core-*.jar", "flyway-sqlserver-*.jar" }) +@ClassPathOverrides({ "org.flywaydb:flyway-core:10.0.0", "com.h2database:h2:2.1.210" }) +@EnabledForJreRange(min = JRE.JAVA_17) +class Flyway10xAutoConfigurationTests { + + private final 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")); + }); + } + +}