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 f9a16c04e65d..1f16fd868f10 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,12 +16,12 @@ package org.springframework.boot.autoconfigure.flyway; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.annotation.PostConstruct; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -104,6 +104,8 @@ public static class FlywayConfiguration { private List flywayCallbacks; + private static final String VENDOR_PLACEHOLDER = "{vendor}"; + public FlywayConfiguration(FlywayProperties properties, ResourceLoader resourceLoader, ObjectProvider dataSource, @FlywayDataSource ObjectProvider flywayDataSource, @@ -117,28 +119,6 @@ public FlywayConfiguration(FlywayProperties properties, this.flywayCallbacks = flywayCallbacks.getIfAvailable(Collections::emptyList); } - @PostConstruct - public void checkLocationExists() { - if (this.properties.isCheckLocation()) { - Assert.state(!this.properties.getLocations().isEmpty(), - "Migration script locations not configured"); - boolean exists = hasAtLeastOneLocation(); - Assert.state(exists, - () -> "Cannot find migrations location in: " + this.properties - .getLocations() - + " (please add migrations or check your Flyway configuration)"); - } - } - - private boolean hasAtLeastOneLocation() { - for (String location : this.properties.getLocations()) { - if (this.resourceLoader.getResource(location).exists()) { - return true; - } - } - return false; - } - @Bean @ConfigurationProperties(prefix = "spring.flyway") public Flyway flyway() { @@ -156,10 +136,61 @@ else if (this.flywayDataSource != null) { } flyway.setCallbacks(this.flywayCallbacks .toArray(new FlywayCallback[this.flywayCallbacks.size()])); - flyway.setLocations(this.properties.getLocations().toArray(new String[0])); + String[] locations = resolveLocations(this.properties.getLocations().toArray(new String[0]), flyway.getDataSource()); + checkLocationExists(locations); + flyway.setLocations(locations); return flyway; } + private static String[] resolveLocations(String[] locations, DataSource dataSource) { + if (usesVendorLocation(locations)) { + try { + String url = (String) JdbcUtils + .extractDatabaseMetaData(dataSource, "getURL"); + DatabaseDriver vendor = DatabaseDriver.fromJdbcUrl(url); + if (vendor != DatabaseDriver.UNKNOWN) { + for (int i = 0; i < locations.length; i++) { + locations[i] = locations[i].replace(VENDOR_PLACEHOLDER, + vendor.getId()); + } + } + } + catch (MetaDataAccessException ex) { + throw new IllegalStateException(ex); + } + } + return locations; + } + + private static boolean usesVendorLocation(String... locations) { + for (String location : locations) { + if (location.contains(VENDOR_PLACEHOLDER)) { + return true; + } + } + return false; + } + + private void checkLocationExists(String... locations) { + if (this.properties.isCheckLocation()) { + Assert.state(locations.length != 0, + "Migration script locations not configured"); + boolean exists = hasAtLeastOneLocation(locations); + Assert.state(exists, + () -> "Cannot find migrations location in: " + Arrays.asList(locations) + + " (please add migrations or check your Flyway configuration)"); + } + } + + private boolean hasAtLeastOneLocation(String... locations) { + for (String location : locations) { + if (this.resourceLoader.getResource(location).exists()) { + return true; + } + } + return false; + } + @Bean @ConditionalOnMissingBean public FlywayMigrationInitializer flywayInitializer(Flyway flyway) { @@ -202,38 +233,13 @@ public FlywayJpaDependencyConfiguration() { private static class SpringBootFlyway extends Flyway { - private static final String VENDOR_PLACEHOLDER = "{vendor}"; - @Override public void setLocations(String... locations) { - if (usesVendorLocation(locations)) { - try { - String url = (String) JdbcUtils - .extractDatabaseMetaData(getDataSource(), "getURL"); - DatabaseDriver vendor = DatabaseDriver.fromJdbcUrl(url); - if (vendor != DatabaseDriver.UNKNOWN) { - for (int i = 0; i < locations.length; i++) { - locations[i] = locations[i].replace(VENDOR_PLACEHOLDER, - vendor.getId()); - } - } - } - catch (MetaDataAccessException ex) { - throw new IllegalStateException(ex); - } - } + locations = FlywayConfiguration.resolveLocations(locations, + getDataSource()); super.setLocations(locations); } - private boolean usesVendorLocation(String... locations) { - for (String location : locations) { - if (location.contains(VENDOR_PLACEHOLDER)) { - return true; - } - } - return false; - } - } /** 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 fbc279c0b86e..8d8006350cf4 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 @@ -255,6 +255,17 @@ public void useVendorDirectory() { }); } + @Test + public void useOneLocationWithVendorDirectory() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) + .withPropertyValues("spring.flyway.locations=classpath:db/vendors/{vendor}") + .run((context) -> { + assertThat(context).hasSingleBean(Flyway.class); + Flyway flyway = context.getBean(Flyway.class); + assertThat(flyway.getLocations()).containsExactly("classpath:db/vendors/h2"); + }); + } + @Test public void callbacksAreConfiguredAndOrdered() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,