Use main DataSource when there are no migration-specific conn details

Fixes gh-35109
This commit is contained in:
Andy Wilkinson 2023-04-24 12:02:37 +01:00
parent 363dc9368d
commit 7ffacf43f3
6 changed files with 52 additions and 103 deletions

View File

@ -24,7 +24,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.sql.DataSource;
@ -85,7 +84,7 @@ import org.springframework.util.StringUtils;
* @author Dominic Gunn
* @author Dan Zheng
* @author András Deák
* @author Semyon Danilov
* @author Semyon Danilo
* @author Chris Bono
* @author Moritz Halbritter
* @author Andy Wilkinson
@ -126,7 +125,7 @@ public class FlywayAutoConfiguration {
@ConditionalOnMissingBean(FlywayConnectionDetails.class)
PropertiesFlywayConnectionDetails flywayConnectionDetails(FlywayProperties properties,
ObjectProvider<JdbcConnectionDetails> jdbcConnectionDetails) {
return new PropertiesFlywayConnectionDetails(properties, jdbcConnectionDetails.getIfAvailable());
return new PropertiesFlywayConnectionDetails(properties);
}
@Deprecated(since = "3.0.0", forRemoval = true)
@ -134,14 +133,15 @@ public class FlywayAutoConfiguration {
ObjectProvider<DataSource> dataSource, ObjectProvider<DataSource> flywayDataSource,
ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,
ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks) {
return flyway(properties, new PropertiesFlywayConnectionDetails(properties, null), resourceLoader,
dataSource, flywayDataSource, fluentConfigurationCustomizers, javaMigrations, callbacks,
return flyway(properties, new PropertiesFlywayConnectionDetails(properties), resourceLoader, dataSource,
null, flywayDataSource, fluentConfigurationCustomizers, javaMigrations, callbacks,
new ResourceProviderCustomizer());
}
@Bean
Flyway flyway(FlywayProperties properties, FlywayConnectionDetails connectionDetails,
ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource,
ObjectProvider<JdbcConnectionDetails> jdbcConnectionDetails,
@FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,
ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks,
@ -412,46 +412,34 @@ public class FlywayAutoConfiguration {
}
/**
* Adapts {@link FlywayProperties} to {@link FlywayConnectionDetails}, using
* {@link JdbcConnectionDetails} as a fallback when Flyway-specific properties have
* not be configured.
* Adapts {@link FlywayProperties} to {@link FlywayConnectionDetails}.
*/
static final class PropertiesFlywayConnectionDetails implements FlywayConnectionDetails {
private final JdbcConnectionDetails fallback;
private final FlywayProperties properties;
PropertiesFlywayConnectionDetails(FlywayProperties properties, JdbcConnectionDetails fallback) {
this.fallback = fallback;
PropertiesFlywayConnectionDetails(FlywayProperties properties) {
this.properties = properties;
}
@Override
public String getUsername() {
return get(this.properties.getUser(), JdbcConnectionDetails::getUsername);
return this.properties.getUser();
}
@Override
public String getPassword() {
return get(this.properties.getPassword(), JdbcConnectionDetails::getPassword);
return this.properties.getPassword();
}
@Override
public String getJdbcUrl() {
return get(this.properties.getUrl(), JdbcConnectionDetails::getJdbcUrl);
return this.properties.getUrl();
}
@Override
public String getDriverClassName() {
return get(this.properties.getDriverClassName(), JdbcConnectionDetails::getDriverClassName);
}
private String get(String primary, Function<JdbcConnectionDetails, String> fallbackProperty) {
if (primary != null) {
return primary;
}
return (this.fallback != null) ? fallbackProperty.apply(this.fallback) : null;
return this.properties.getDriverClassName();
}
}

View File

@ -28,33 +28,37 @@ import org.springframework.boot.jdbc.DatabaseDriver;
public interface FlywayConnectionDetails extends ConnectionDetails {
/**
* Username for the database.
* @return the username for the database
* Username for the database or {@code null} if no Flyway-specific configuration is
* required.
* @return the username for the database or {@code null}
*/
String getUsername();
/**
* Password for the database.
* @return the password for the database
* Password for the database or {@code null} if no Flyway-specific configuration is
* required.
* @return the password for the database or {@code null}
*/
String getPassword();
/**
* JDBC URL for the database.
* @return the JDBC URL for the database
* JDBC URL for the database or {@code null} if no Flyway-specific configuration is
* required.
* @return the JDBC URL for the database or {@code null}
*/
String getJdbcUrl();
/**
* The name of the JDBC driver class. Defaults to the class name of the driver
* specified in the JDBC URL.
* @return the JDBC driver class name
* specified in the JDBC URL or {@code null} when no JDBC URL is configured.
* @return the JDBC driver class name or {@code null}
* @see #getJdbcUrl()
* @see DatabaseDriver#fromJdbcUrl(String)
* @see DatabaseDriver#getDriverClassName()
*/
default String getDriverClassName() {
return DatabaseDriver.fromJdbcUrl(getJdbcUrl()).getDriverClassName();
String jdbcUrl = getJdbcUrl();
return (jdbcUrl != null) ? DatabaseDriver.fromJdbcUrl(jdbcUrl).getDriverClassName() : null;
}
}

View File

@ -16,8 +16,6 @@
package org.springframework.boot.autoconfigure.liquibase;
import java.util.function.Function;
import javax.sql.DataSource;
import liquibase.change.DatabaseChange;
@ -33,8 +31,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.flyway.FlywayConnectionDetails;
import org.springframework.boot.autoconfigure.flyway.FlywayProperties;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseAutoConfigurationRuntimeHints;
@ -93,7 +89,7 @@ public class LiquibaseAutoConfiguration {
@ConditionalOnMissingBean(LiquibaseConnectionDetails.class)
PropertiesLiquibaseConnectionDetails liquibaseConnectionDetails(LiquibaseProperties properties,
ObjectProvider<JdbcConnectionDetails> jdbcConnectionDetails) {
return new PropertiesLiquibaseConnectionDetails(properties, jdbcConnectionDetails.getIfAvailable());
return new PropertiesLiquibaseConnectionDetails(properties);
}
@Bean
@ -198,46 +194,35 @@ public class LiquibaseAutoConfiguration {
}
/**
* Adapts {@link FlywayProperties} to {@link FlywayConnectionDetails}, using
* {@link JdbcConnectionDetails} as a fallback when Flyway-specific properties have
* not be configured.
* Adapts {@link LiquibaseProperties} to {@link LiquibaseConnectionDetails}.
*/
static final class PropertiesLiquibaseConnectionDetails implements LiquibaseConnectionDetails {
private final JdbcConnectionDetails fallback;
private final LiquibaseProperties properties;
PropertiesLiquibaseConnectionDetails(LiquibaseProperties properties, JdbcConnectionDetails fallback) {
this.fallback = fallback;
PropertiesLiquibaseConnectionDetails(LiquibaseProperties properties) {
this.properties = properties;
}
@Override
public String getUsername() {
return get(this.properties.getUser(), JdbcConnectionDetails::getUsername);
return this.properties.getUser();
}
@Override
public String getPassword() {
return get(this.properties.getPassword(), JdbcConnectionDetails::getPassword);
return this.properties.getPassword();
}
@Override
public String getJdbcUrl() {
return get(this.properties.getUrl(), JdbcConnectionDetails::getJdbcUrl);
return this.properties.getUrl();
}
@Override
public String getDriverClassName() {
return get(this.properties.getDriverClassName(), JdbcConnectionDetails::getDriverClassName);
}
private String get(String primary, Function<JdbcConnectionDetails, String> fallbackProperty) {
if (primary != null) {
return primary;
}
return (this.fallback != null) ? fallbackProperty.apply(this.fallback) : null;
String driverClassName = this.properties.getDriverClassName();
return (driverClassName != null) ? driverClassName : LiquibaseConnectionDetails.super.getDriverClassName();
}
}

View File

@ -28,33 +28,37 @@ import org.springframework.boot.jdbc.DatabaseDriver;
public interface LiquibaseConnectionDetails extends ConnectionDetails {
/**
* Username for the database.
* @return the username for the database
* Username for the database or {@code null} if no Liquibase-specific configuration is
* required.
* @return the username for the database or {@code null}
*/
String getUsername();
/**
* Password for the database.
* @return the password for the database
* Password for the database or {@code null} if no Liquibase-specific configuration is
* required.
* @return the password for the database or {@code null}
*/
String getPassword();
/**
* JDBC URL for the database.
* @return the JDBC URL for the database
* JDBC URL for the database or {@code null} if no Liquibase-specific configuration is
* required.
* @return the JDBC URL for the database or {@code null}
*/
String getJdbcUrl();
/**
* The name of the JDBC driver class. Defaults to the class name of the driver
* specified in the JDBC URL.
* @return the JDBC driver class name
* specified in the JDBC URL or {@code null} when no JDBC URL is configured.
* @return the JDBC driver class name or {@code null}
* @see #getJdbcUrl()
* @see DatabaseDriver#fromJdbcUrl(String)
* @see DatabaseDriver#getDriverClassName()
*/
default String getDriverClassName() {
return DatabaseDriver.fromJdbcUrl(getJdbcUrl()).getDriverClassName();
String jdbcUrl = getJdbcUrl();
return (jdbcUrl != null) ? DatabaseDriver.fromJdbcUrl(jdbcUrl).getDriverClassName() : null;
}
}

View File

@ -122,16 +122,6 @@ class FlywayAutoConfigurationTests {
});
}
@Test
void createsDataSourceWithNoDataSourceBeanAndJdbcConnectionDetails() {
this.contextRunner
.withUserConfiguration(JdbcConnectionDetailsConfiguration.class, MockFlywayMigrationStrategy.class)
.run((context) -> {
assertThat(context).hasSingleBean(Flyway.class);
assertThat(context.getBean(Flyway.class).getConfiguration().getDataSource()).isNotNull();
});
}
@Test
void backsOffWithFlywayUrlAndNoSpringJdbc() {
this.contextRunner.withPropertyValues("spring.flyway.url:jdbc:hsqldb:mem:" + UUID.randomUUID())
@ -193,7 +183,7 @@ class FlywayAutoConfigurationTests {
}
@Test
void jdbcConnectionDetailsAreUsedOverDataSourceProperties() {
void shouldUseMainDataSourceWhenThereIsNoFlywaySpecificConfiguration() {
this.contextRunner
.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JdbcConnectionDetailsConfiguration.class,
MockFlywayMigrationStrategy.class)
@ -201,16 +191,8 @@ class FlywayAutoConfigurationTests {
"spring.datasource.password=some-password",
"spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver")
.run((context) -> {
assertThat(context).hasSingleBean(Flyway.class);
Flyway flyway = context.getBean(Flyway.class);
DataSource dataSource = flyway.getConfiguration().getDataSource();
assertThat(dataSource).isInstanceOf(SimpleDriverDataSource.class);
SimpleDriverDataSource simpleDriverDataSource = (SimpleDriverDataSource) dataSource;
assertThat(simpleDriverDataSource.getUrl())
.isEqualTo("jdbc:postgresql://database.example.com:12345/database-1");
assertThat(simpleDriverDataSource.getUsername()).isEqualTo("user-1");
assertThat(simpleDriverDataSource.getPassword()).isEqualTo("secret-1");
assertThat(simpleDriverDataSource.getDriver()).isInstanceOf(Driver.class);
assertThat(flyway.getConfiguration().getDataSource()).isSameAs(context.getBean(DataSource.class));
});
}

View File

@ -101,18 +101,6 @@ class LiquibaseAutoConfigurationTests {
}));
}
@Test
void createsDataSourceWithNoDataSourceBeanAndJdbcConnectionDetails() {
this.contextRunner.withSystemProperties("shouldRun=false")
.withUserConfiguration(JdbcConnectionDetailsConfiguration.class)
.run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo("jdbc:postgresql://database.example.com:12345/database-1");
assertThat(dataSource.getUsername()).isEqualTo("user-1");
assertThat(dataSource.getPassword()).isEqualTo("secret-1");
}));
}
@Test
void backsOffWithLiquibaseUrlAndNoSpringJdbc() {
this.contextRunner.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:" + UUID.randomUUID())
@ -133,15 +121,13 @@ class LiquibaseAutoConfigurationTests {
}
@Test
void jdbcConnectionDetailsAreUsedIfAvailable() {
void shouldUseMainDataSourceWhenThereIsNoLiquibaseSpecificConfiguration() {
this.contextRunner.withSystemProperties("shouldRun=false")
.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JdbcConnectionDetailsConfiguration.class)
.run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo("jdbc:postgresql://database.example.com:12345/database-1");
assertThat(dataSource.getUsername()).isEqualTo("user-1");
assertThat(dataSource.getPassword()).isEqualTo("secret-1");
}));
.run((context) -> {
SpringLiquibase liquibase = context.getBean(SpringLiquibase.class);
assertThat(liquibase.getDataSource()).isSameAs(context.getBean(DataSource.class));
});
}
@Test