Skip to content

Commit bc322ff

Browse files
committed
Merge pull request #10387 from eddumelendez/flyway_check_vendor_locations
* pr/10387: Polish location check with vendor placeholder Support location check with vendor placeholder
2 parents 3be667c + 72862b5 commit bc322ff

File tree

2 files changed

+87
-41
lines changed

2 files changed

+87
-41
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616

1717
package org.springframework.boot.autoconfigure.flyway;
1818

19+
import java.util.Arrays;
20+
import java.util.Collection;
1921
import java.util.Collections;
2022
import java.util.HashSet;
2123
import java.util.List;
2224
import java.util.Set;
2325

24-
import javax.annotation.PostConstruct;
2526
import javax.persistence.EntityManagerFactory;
2627
import javax.sql.DataSource;
2728

@@ -117,28 +118,6 @@ public FlywayConfiguration(FlywayProperties properties,
117118
this.flywayCallbacks = flywayCallbacks.getIfAvailable(Collections::emptyList);
118119
}
119120

120-
@PostConstruct
121-
public void checkLocationExists() {
122-
if (this.properties.isCheckLocation()) {
123-
Assert.state(!this.properties.getLocations().isEmpty(),
124-
"Migration script locations not configured");
125-
boolean exists = hasAtLeastOneLocation();
126-
Assert.state(exists,
127-
() -> "Cannot find migrations location in: " + this.properties
128-
.getLocations()
129-
+ " (please add migrations or check your Flyway configuration)");
130-
}
131-
}
132-
133-
private boolean hasAtLeastOneLocation() {
134-
for (String location : this.properties.getLocations()) {
135-
if (this.resourceLoader.getResource(location).exists()) {
136-
return true;
137-
}
138-
}
139-
return false;
140-
}
141-
142121
@Bean
143122
@ConfigurationProperties(prefix = "spring.flyway")
144123
public Flyway flyway() {
@@ -156,10 +135,34 @@ else if (this.flywayDataSource != null) {
156135
}
157136
flyway.setCallbacks(this.flywayCallbacks
158137
.toArray(new FlywayCallback[this.flywayCallbacks.size()]));
159-
flyway.setLocations(this.properties.getLocations().toArray(new String[0]));
138+
String[] locations = new LocationResolver(flyway.getDataSource())
139+
.resolveLocations(this.properties.getLocations());
140+
checkLocationExists(locations);
141+
flyway.setLocations(locations);
160142
return flyway;
161143
}
162144

145+
private void checkLocationExists(String... locations) {
146+
if (this.properties.isCheckLocation()) {
147+
Assert.state(locations.length != 0,
148+
"Migration script locations not configured");
149+
boolean exists = hasAtLeastOneLocation(locations);
150+
Assert.state(exists,
151+
() -> "Cannot find migrations location in: " + Arrays.asList(
152+
locations)
153+
+ " (please add migrations or check your Flyway configuration)");
154+
}
155+
}
156+
157+
private boolean hasAtLeastOneLocation(String... locations) {
158+
for (String location : locations) {
159+
if (this.resourceLoader.getResource(location).exists()) {
160+
return true;
161+
}
162+
}
163+
return false;
164+
}
165+
163166
@Bean
164167
@ConditionalOnMissingBean
165168
public FlywayMigrationInitializer flywayInitializer(Flyway flyway) {
@@ -202,27 +205,57 @@ public FlywayJpaDependencyConfiguration() {
202205

203206
private static class SpringBootFlyway extends Flyway {
204207

205-
private static final String VENDOR_PLACEHOLDER = "{vendor}";
206-
207208
@Override
208209
public void setLocations(String... locations) {
210+
super.setLocations(
211+
new LocationResolver(getDataSource()).resolveLocations(locations));
212+
}
213+
214+
}
215+
216+
private static class LocationResolver {
217+
218+
private static final String VENDOR_PLACEHOLDER = "{vendor}";
219+
220+
private final DataSource dataSource;
221+
222+
public LocationResolver(DataSource dataSource) {
223+
this.dataSource = dataSource;
224+
}
225+
226+
public String[] resolveLocations(Collection<String> locations) {
227+
return resolveLocations(locations.toArray(new String[locations.size()]));
228+
}
229+
230+
public String[] resolveLocations(String[] locations) {
209231
if (usesVendorLocation(locations)) {
210-
try {
211-
String url = (String) JdbcUtils
212-
.extractDatabaseMetaData(getDataSource(), "getURL");
213-
DatabaseDriver vendor = DatabaseDriver.fromJdbcUrl(url);
214-
if (vendor != DatabaseDriver.UNKNOWN) {
215-
for (int i = 0; i < locations.length; i++) {
216-
locations[i] = locations[i].replace(VENDOR_PLACEHOLDER,
217-
vendor.getId());
218-
}
219-
}
220-
}
221-
catch (MetaDataAccessException ex) {
222-
throw new IllegalStateException(ex);
223-
}
232+
DatabaseDriver databaseDriver = getDatabaseDriver();
233+
return replaceVendorLocations(locations, databaseDriver);
224234
}
225-
super.setLocations(locations);
235+
return locations;
236+
}
237+
238+
private String[] replaceVendorLocations(String[] locations,
239+
DatabaseDriver databaseDriver) {
240+
if (databaseDriver == DatabaseDriver.UNKNOWN) {
241+
return locations;
242+
}
243+
String vendor = databaseDriver.getId();
244+
return Arrays.stream(locations)
245+
.map((location) -> location.replace(VENDOR_PLACEHOLDER, vendor))
246+
.toArray(String[]::new);
247+
}
248+
249+
private DatabaseDriver getDatabaseDriver() {
250+
try {
251+
String url = (String) JdbcUtils.extractDatabaseMetaData(this.dataSource,
252+
"getURL");
253+
return DatabaseDriver.fromJdbcUrl(url);
254+
}
255+
catch (MetaDataAccessException ex) {
256+
throw new IllegalStateException(ex);
257+
}
258+
226259
}
227260

228261
private boolean usesVendorLocation(String... locations) {

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,19 @@ public void useVendorDirectory() {
255255
});
256256
}
257257

258+
@Test
259+
public void useOneLocationWithVendorDirectory() {
260+
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
261+
.withPropertyValues(
262+
"spring.flyway.locations=classpath:db/vendors/{vendor}")
263+
.run((context) -> {
264+
assertThat(context).hasSingleBean(Flyway.class);
265+
Flyway flyway = context.getBean(Flyway.class);
266+
assertThat(flyway.getLocations())
267+
.containsExactly("classpath:db/vendors/h2");
268+
});
269+
}
270+
258271
@Test
259272
public void callbacksAreConfiguredAndOrdered() {
260273
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class,

0 commit comments

Comments
 (0)