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 0cb2f73e0b..2a787e519e 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 @@ -16,7 +16,6 @@ package org.springframework.boot.autoconfigure.flyway; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -63,7 +62,6 @@ import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; -import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -163,15 +161,10 @@ public class FlywayAutoConfiguration { private void checkLocationExists(DataSource dataSource, FlywayProperties properties, ResourceLoader resourceLoader) { if (properties.isCheckLocation()) { - String[] locations = new LocationResolver(dataSource) + List locations = new LocationResolver(dataSource) .resolveLocations(properties.getLocations()); - Assert.state(locations.length != 0, - "Migration script locations not configured"); - boolean exists = hasAtLeastOneLocation(resourceLoader, locations); - if (!exists) { - throw new FlywayMigrationScriptNotFoundException( - "Cannot find migrations in the specified location", - Arrays.asList(locations)); + if (!hasAtLeastOneLocation(resourceLoader, locations)) { + throw new FlywayMigrationScriptMissingException(locations); } } } @@ -180,7 +173,7 @@ public class FlywayAutoConfiguration { FlywayProperties properties) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); String[] locations = new LocationResolver(configuration.getDataSource()) - .resolveLocations(properties.getLocations()); + .resolveLocations(properties.getLocations()).toArray(new String[0]); map.from(locations).to(configuration::locations); map.from(properties.getEncoding()).to(configuration::encoding); map.from(properties.getConnectRetries()).to(configuration::connectRetries); @@ -257,7 +250,7 @@ public class FlywayAutoConfiguration { } private boolean hasAtLeastOneLocation(ResourceLoader resourceLoader, - String... locations) { + Collection locations) { for (String location : locations) { if (resourceLoader.getResource(normalizePrefix(location)).exists()) { return true; @@ -387,11 +380,7 @@ public class FlywayAutoConfiguration { this.dataSource = dataSource; } - public String[] resolveLocations(Collection locations) { - return resolveLocations(StringUtils.toStringArray(locations)); - } - - public String[] resolveLocations(String[] locations) { + public List resolveLocations(List locations) { if (usesVendorLocation(locations)) { DatabaseDriver databaseDriver = getDatabaseDriver(); return replaceVendorLocations(locations, databaseDriver); @@ -399,15 +388,15 @@ public class FlywayAutoConfiguration { return locations; } - private String[] replaceVendorLocations(String[] locations, + private List replaceVendorLocations(List locations, DatabaseDriver databaseDriver) { if (databaseDriver == DatabaseDriver.UNKNOWN) { return locations; } String vendor = databaseDriver.getId(); - return Arrays.stream(locations) + return locations.stream() .map((location) -> location.replace(VENDOR_PLACEHOLDER, vendor)) - .toArray(String[]::new); + .collect(Collectors.toList()); } private DatabaseDriver getDatabaseDriver() { @@ -421,7 +410,7 @@ public class FlywayAutoConfiguration { } - private boolean usesVendorLocation(String... locations) { + private boolean usesVendorLocation(Collection locations) { for (String location : locations) { if (location.contains(VENDOR_PLACEHOLDER)) { return true; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptNotFoundException.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingException.java similarity index 61% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptNotFoundException.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingException.java index 6547d8d82b..8bfa907613 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptNotFoundException.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingException.java @@ -16,22 +16,25 @@ package org.springframework.boot.autoconfigure.flyway; +import java.util.ArrayList; import java.util.List; /** - * Exception thrown when no {@code flyway migration script} is available. + * Exception thrown when no Flyway migration script is available. * * @author Anand Shastri + * @author Stephane Nicoll + * @since 2.2.0 */ - -public class FlywayMigrationScriptNotFoundException extends RuntimeException { +public class FlywayMigrationScriptMissingException extends RuntimeException { private final List locations; - public FlywayMigrationScriptNotFoundException(String message, - List locations) { - super(message); - this.locations = locations; + FlywayMigrationScriptMissingException(List locations) { + super(locations.isEmpty() ? "Migration script locations not configured" + : "Cannot find migrations location in: " + locations + + " (please add migrations or check your Flyway configuration)"); + this.locations = new ArrayList<>(locations); } public List getLocations() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java index b067cfd969..bb0bb88c54 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzer.java @@ -21,19 +21,32 @@ import org.springframework.boot.diagnostics.FailureAnalysis; /** * A {@code FailureAnalyzer} that performs analysis of failures caused by a - * {@code FlywayMigrationScriptNotFoundException}. + * {@link FlywayMigrationScriptMissingException}. * * @author Anand Shastri + * @author Stephane Nicoll */ -public class FlywayMigrationScriptMissingFailureAnalyzer - extends AbstractFailureAnalyzer { +class FlywayMigrationScriptMissingFailureAnalyzer + extends AbstractFailureAnalyzer { @Override protected FailureAnalysis analyze(Throwable rootFailure, - FlywayMigrationScriptNotFoundException cause) { - return new FailureAnalysis( - "Cannot find migrations location in " + cause.getLocations(), - " please add migrations or check your Flyway configuration", cause); + FlywayMigrationScriptMissingException cause) { + StringBuilder description = new StringBuilder("Flyway failed to initialize: "); + if (cause.getLocations().isEmpty()) { + return new FailureAnalysis(description + .append("no migration scripts location is configured").toString(), + "Check your Flyway configuration", cause); + } + else { + description.append(String.format( + "none of the following migration scripts locations could be found:%n%n")); + cause.getLocations().forEach((location) -> description + .append(String.format("\t- %s%n", location))); + return new FailureAnalysis(description.toString(), + "Review the locations above or check your Flyway configuration", + cause); + } } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 03dd3e4421..e22fb697c9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -141,6 +141,7 @@ org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAuto # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ +org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\ org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index 49aae3588c..f101ee5ffd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -209,7 +209,7 @@ public class FlywayAutoConfigurationTests { assertThat(context).getFailure() .isInstanceOf(BeanCreationException.class); assertThat(context).getFailure() - .hasMessageContaining("Cannot find migrations in"); + .hasMessageContaining("Cannot find migrations location in"); }); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzerTests.java index 1c4d48a0e5..936cc545b9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationScriptMissingFailureAnalyzerTests.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.flyway; -import java.util.Collections; +import java.util.Arrays; import org.junit.Test; @@ -25,25 +25,35 @@ import org.springframework.boot.diagnostics.FailureAnalysis; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link FlywayMigrationScriptMissingFailureAnalyzer} + * Tests for {@link FlywayMigrationScriptMissingFailureAnalyzer}. * * @author Anand Shastri */ public class FlywayMigrationScriptMissingFailureAnalyzerTests { - private final FlywayMigrationScriptMissingFailureAnalyzer analyzer = new FlywayMigrationScriptMissingFailureAnalyzer(); - @Test - public void analysisForFlywayScriptMissingFailure() { - FailureAnalysis failureAnalysis = this.analyzer - .analyze(new FlywayMigrationScriptNotFoundException( - "Migration script locations not configured", - Collections.singletonList("classpath:db/migration"))); - + public void analysisForMissingScriptLocation() { + FailureAnalysis failureAnalysis = performAnalysis(); assertThat(failureAnalysis.getDescription()) - .endsWith("Cannot find migrations location in [classpath:db/migration]"); + .contains("no migration scripts location is configured"); assertThat(failureAnalysis.getAction()) - .endsWith(" please add migrations or check your Flyway configuration"); + .contains("Check your Flyway configuration"); + } + + @Test + public void analysisForScriptLocationsNotFound() { + FailureAnalysis failureAnalysis = performAnalysis("classpath:db/migration"); + assertThat(failureAnalysis.getDescription()).contains( + "none of the following migration scripts locations could be found") + .contains("classpath:db/migration"); + assertThat(failureAnalysis.getAction()).contains( + "Review the locations above or check your Flyway configuration"); + } + + private FailureAnalysis performAnalysis(String... locations) { + FlywayMigrationScriptMissingException exception = new FlywayMigrationScriptMissingException( + Arrays.asList(locations)); + return new FlywayMigrationScriptMissingFailureAnalyzer().analyze(exception); } } diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index 888826f91d..0e09bea33e 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -50,8 +50,7 @@ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnaly org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ -org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\ -org.springframework.boot.diagnostics.analyzer.FlywayMigrationScriptMissingFailureAnalyzer +org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\