Skip to content

Commit 8807215

Browse files
committed
Polish "Auto-configure Flyway and Liquibase when there's a URL but no DataSource"
See gh-16850
1 parent 3ca73bf commit 8807215

File tree

12 files changed

+64
-196
lines changed

12 files changed

+64
-196
lines changed

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

+25-6
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@
3636
import org.springframework.beans.factory.ObjectProvider;
3737
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3838
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
39+
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
3940
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
4041
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
4142
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
4243
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
4344
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
45+
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayDataSourceCondition;
4446
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
4547
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
4648
import org.springframework.boot.autoconfigure.jdbc.JdbcOperationsDependsOnPostProcessor;
@@ -52,6 +54,7 @@
5254
import org.springframework.boot.context.properties.PropertyMapper;
5355
import org.springframework.boot.jdbc.DatabaseDriver;
5456
import org.springframework.context.annotation.Bean;
57+
import org.springframework.context.annotation.Conditional;
5558
import org.springframework.context.annotation.Configuration;
5659
import org.springframework.core.convert.TypeDescriptor;
5760
import org.springframework.core.convert.converter.GenericConverter;
@@ -82,8 +85,8 @@
8285
@SuppressWarnings("deprecation")
8386
@Configuration(proxyBeanMethods = false)
8487
@ConditionalOnClass(Flyway.class)
85-
@ConditionalOnProperty(prefix = FlywayProperties.PROPERTIES_PREFIX, name = "enabled",
86-
matchIfMissing = true)
88+
@Conditional(FlywayDataSourceCondition.class)
89+
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", matchIfMissing = true)
8790
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
8891
JdbcTemplateAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
8992
public class FlywayAutoConfiguration {
@@ -152,11 +155,8 @@ private DataSource configureDataSource(FluentConfiguration configuration,
152155
else if (flywayDataSource != null) {
153156
configuration.dataSource(flywayDataSource);
154157
}
155-
else if (dataSource != null) {
156-
configuration.dataSource(dataSource);
157-
}
158158
else {
159-
throw new FlywayDataSourceMissingException();
159+
configuration.dataSource(dataSource);
160160
}
161161
return configuration.getDataSource();
162162
}
@@ -465,4 +465,23 @@ public Object convert(Object source, TypeDescriptor sourceType,
465465

466466
}
467467

468+
static final class FlywayDataSourceCondition extends AnyNestedCondition {
469+
470+
FlywayDataSourceCondition() {
471+
super(ConfigurationPhase.REGISTER_BEAN);
472+
}
473+
474+
@ConditionalOnBean(DataSource.class)
475+
private static final class DataSourceBeanCondition {
476+
477+
}
478+
479+
@ConditionalOnProperty(prefix = "spring.flyway", name = "url",
480+
matchIfMissing = false)
481+
private static final class FlywayUrlCondition {
482+
483+
}
484+
485+
}
486+
468487
}

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

-34
This file was deleted.

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

-39
This file was deleted.

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,9 @@
3535
* @author Stephane Nicoll
3636
* @since 1.1.0
3737
*/
38-
@ConfigurationProperties(prefix = FlywayProperties.PROPERTIES_PREFIX)
38+
@ConfigurationProperties(prefix = "spring.flyway")
3939
public class FlywayProperties {
4040

41-
public static final String PROPERTIES_PREFIX = "spring.flyway";
42-
4341
/**
4442
* Whether to enable flyway.
4543
*/

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java

+28-8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.beans.factory.ObjectProvider;
2929
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3030
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
3132
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3233
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3334
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -37,10 +38,12 @@
3738
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
3839
import org.springframework.boot.autoconfigure.jdbc.JdbcOperationsDependsOnPostProcessor;
3940
import org.springframework.boot.autoconfigure.jdbc.NamedParameterJdbcOperationsDependsOnPostProcessor;
41+
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseDataSourceCondition;
4042
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
4143
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4244
import org.springframework.boot.jdbc.DataSourceBuilder;
4345
import org.springframework.context.annotation.Bean;
46+
import org.springframework.context.annotation.Conditional;
4447
import org.springframework.context.annotation.Configuration;
4548
import org.springframework.context.annotation.Import;
4649
import org.springframework.core.io.Resource;
@@ -65,8 +68,9 @@
6568
*/
6669
@Configuration(proxyBeanMethods = false)
6770
@ConditionalOnClass({ SpringLiquibase.class, DatabaseChange.class })
68-
@ConditionalOnProperty(prefix = LiquibaseProperties.PROPERTIES_PREFIX, name = "enabled",
71+
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled",
6972
matchIfMissing = true)
73+
@Conditional(LiquibaseDataSourceCondition.class)
7074
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
7175
HibernateJpaAutoConfiguration.class })
7276
public class LiquibaseAutoConfiguration {
@@ -140,20 +144,17 @@ private SpringLiquibase createSpringLiquibase(DataSource liquibaseDatasource,
140144
liquibase.setDataSource(liquibaseDataSource);
141145
return liquibase;
142146
}
143-
else if (this.properties.isCreateDataSource()) {
144-
SpringLiquibase liquibase = new DataSourceClosingSpringLiquibase();
145-
liquibase.setDataSource(createNewDataSource(dataSourceProperties));
146-
return liquibase;
147-
}
148-
throw new LiquibaseDataSourceMissingException();
147+
SpringLiquibase liquibase = new DataSourceClosingSpringLiquibase();
148+
liquibase.setDataSource(createNewDataSource(dataSourceProperties));
149+
return liquibase;
149150
}
150151

151152
private DataSource getDataSource(DataSource liquibaseDataSource,
152153
DataSource dataSource) {
153154
if (liquibaseDataSource != null) {
154155
return liquibaseDataSource;
155156
}
156-
if (!this.properties.isCreateDataSource()) {
157+
if (this.properties.getUrl() == null && this.properties.getUser() == null) {
157158
return dataSource;
158159
}
159160
return null;
@@ -227,4 +228,23 @@ public LiquibaseNamedParameterJdbcOperationsDependencyConfiguration() {
227228

228229
}
229230

231+
static final class LiquibaseDataSourceCondition extends AnyNestedCondition {
232+
233+
LiquibaseDataSourceCondition() {
234+
super(ConfigurationPhase.REGISTER_BEAN);
235+
}
236+
237+
@ConditionalOnBean(DataSource.class)
238+
private static final class DataSourceBeanCondition {
239+
240+
}
241+
242+
@ConditionalOnProperty(prefix = "spring.liquibase", name = "url",
243+
matchIfMissing = false)
244+
private static final class LiquibaseUrlCondition {
245+
246+
}
247+
248+
}
249+
230250
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseDataSourceMissingException.java

-34
This file was deleted.

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseDataSourceMissingFailureAnalyzer.java

-39
This file was deleted.

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,9 @@
3030
* @author Marcel Overdijk
3131
* @since 1.1.0
3232
*/
33-
@ConfigurationProperties(prefix = LiquibaseProperties.PROPERTIES_PREFIX,
34-
ignoreUnknownFields = false)
33+
@ConfigurationProperties(prefix = "spring.liquibase", ignoreUnknownFields = false)
3534
public class LiquibaseProperties {
3635

37-
public static final String PROPERTIES_PREFIX = "spring.liquibase";
38-
3936
/**
4037
* Change log configuration path.
4138
*/
@@ -219,10 +216,6 @@ public void setPassword(String password) {
219216
this.password = password;
220217
}
221218

222-
public boolean isCreateDataSource() {
223-
return this.url != null || this.user != null;
224-
}
225-
226219
public String getUrl() {
227220
return this.url;
228221
}

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

-2
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAuto
146146
org.springframework.boot.diagnostics.FailureAnalyzer=\
147147
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
148148
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
149-
org.springframework.boot.autoconfigure.flyway.FlywayDataSourceMissingFailureAnalyzer,\
150-
org.springframework.boot.autoconfigure.liquibase.LiquibaseDataSourceMissingFailureAnalyzer,\
151149
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
152150
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
153151
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

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

+4-10
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,13 @@ public class FlywayAutoConfigurationTests {
7979
.withPropertyValues("spring.datasource.generate-unique-name=true");
8080

8181
@Test
82-
public void noDataSource() {
83-
this.contextRunner.run((context) -> {
84-
assertThat(context).hasFailed();
85-
assertThat(context).getFailure().isInstanceOf(BeanCreationException.class);
86-
assertThat(context).getFailure()
87-
.hasRootCauseInstanceOf(FlywayDataSourceMissingException.class);
88-
assertThat(context).getFailure()
89-
.hasMessageContaining("Flyway is present in classpath and enabled");
90-
});
82+
public void backsOffWithNoDataSourceBeanAndNoFlywayUrl() {
83+
this.contextRunner
84+
.run((context) -> assertThat(context).doesNotHaveBean(Flyway.class));
9185
}
9286

9387
@Test
94-
public void noDataSourceCreateOneWithUrl() {
88+
public void createsDataSourceWithNoDataSourceBeanAndFlywayUrl() {
9589
this.contextRunner
9690
.withPropertyValues(
9791
"spring.flyway.url:jdbc:hsqldb:mem:" + UUID.randomUUID())

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java

+4-10
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,13 @@ public void init() {
7878
.withPropertyValues("spring.datasource.generate-unique-name=true");
7979

8080
@Test
81-
public void noDataSource() {
82-
this.contextRunner.run((context) -> {
83-
assertThat(context).hasFailed();
84-
assertThat(context).getFailure().isInstanceOf(BeanCreationException.class);
85-
assertThat(context).getFailure()
86-
.hasRootCauseInstanceOf(LiquibaseDataSourceMissingException.class);
87-
assertThat(context).getFailure().hasMessageContaining(
88-
"Liquibase is present in classpath and enabled");
89-
});
81+
public void backsOffWithNoDataSourceBeanAndNoLiquibaseUrl() {
82+
this.contextRunner.run(
83+
(context) -> assertThat(context).doesNotHaveBean(SpringLiquibase.class));
9084
}
9185

9286
@Test
93-
public void noDataSourceCreateOneWithUrl() {
87+
public void createsDataSourceWithNoDataSourceBeanAndLiquibaseUrl() {
9488
this.contextRunner
9589
.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:liquibase")
9690
.run(assertLiquibase((liquibase) -> {

0 commit comments

Comments
 (0)