Commit 8ba45cc6 authored by Phillip Webb's avatar Phillip Webb

Allow DB migrations without DataSourceProperties

Update `FlywayAutoConfiguration`, `LiquibaseAutoConfiguration` and
`DataSourceInitializer` classes so that they no longer depend on
`DataSourceProperties`. DB migrations can now be performed against
a `@Bean` defined primary `DataSource` with an alternative
username/password.

This update also removed using fallback properties when a custom
connection `url` is defined with Flyway or Liquibase. We now assume
that `username`, `password` and `driver-class-name` will be provided
if the default values are unacceptable. Our previous logic was
particularly flawed if a custom URL caused a change of driver type.

Closes gh-25643
parent 85f1e2c9
...@@ -23,7 +23,6 @@ import java.util.HashSet; ...@@ -23,7 +23,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.sql.DataSource; import javax.sql.DataSource;
...@@ -44,12 +43,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean ...@@ -44,12 +43,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayDataSourceCondition; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayDataSourceCondition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer; import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -59,8 +58,10 @@ import org.springframework.context.annotation.Import; ...@@ -59,8 +58,10 @@ import org.springframework.context.annotation.Import;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -103,19 +104,17 @@ public class FlywayAutoConfiguration { ...@@ -103,19 +104,17 @@ public class FlywayAutoConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(Flyway.class) @ConditionalOnMissingBean(Flyway.class)
@EnableConfigurationProperties({ DataSourceProperties.class, FlywayProperties.class }) @EnableConfigurationProperties(FlywayProperties.class)
public static class FlywayConfiguration { public static class FlywayConfiguration {
@Bean @Bean
public Flyway flyway(FlywayProperties properties, DataSourceProperties dataSourceProperties, public Flyway flyway(FlywayProperties properties, ResourceLoader resourceLoader,
ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource, ObjectProvider<DataSource> dataSource, @FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
@FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers, ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,
ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks) { ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks) {
FluentConfiguration configuration = new FluentConfiguration(resourceLoader.getClassLoader()); FluentConfiguration configuration = new FluentConfiguration(resourceLoader.getClassLoader());
DataSource dataSourceToMigrate = configureDataSource(configuration, properties, dataSourceProperties, configureDataSource(configuration, properties, flywayDataSource.getIfAvailable(), dataSource.getIfUnique());
flywayDataSource.getIfAvailable(), dataSource.getIfUnique()); checkLocationExists(configuration.getDataSource(), properties, resourceLoader);
checkLocationExists(dataSourceToMigrate, properties, resourceLoader);
configureProperties(configuration, properties); configureProperties(configuration, properties);
List<Callback> orderedCallbacks = callbacks.orderedStream().collect(Collectors.toList()); List<Callback> orderedCallbacks = callbacks.orderedStream().collect(Collectors.toList());
configureCallbacks(configuration, orderedCallbacks); configureCallbacks(configuration, orderedCallbacks);
...@@ -126,21 +125,39 @@ public class FlywayAutoConfiguration { ...@@ -126,21 +125,39 @@ public class FlywayAutoConfiguration {
return configuration.load(); return configuration.load();
} }
private DataSource configureDataSource(FluentConfiguration configuration, FlywayProperties properties, private void configureDataSource(FluentConfiguration configuration, FlywayProperties properties,
DataSourceProperties dataSourceProperties, DataSource flywayDataSource, DataSource dataSource) { DataSource flywayDataSource, DataSource dataSource) {
if (properties.isCreateDataSource()) { DataSource migrationDataSource = getMigrationDataSource(properties, flywayDataSource, dataSource);
String url = getProperty(properties::getUrl, dataSourceProperties::determineUrl); configuration.dataSource(migrationDataSource);
String user = getProperty(properties::getUser, dataSourceProperties::determineUsername); }
String password = getProperty(properties::getPassword, dataSourceProperties::determinePassword);
configuration.dataSource(url, user, password); private DataSource getMigrationDataSource(FlywayProperties properties, DataSource flywayDataSource,
DataSource dataSource) {
if (flywayDataSource != null) {
return flywayDataSource;
} }
else if (flywayDataSource != null) { if (properties.getUrl() != null) {
configuration.dataSource(flywayDataSource); DataSourceBuilder<?> builder = DataSourceBuilder.create().type(SimpleDriverDataSource.class);
builder.url(properties.getUrl());
applyCommonBuilderProperties(properties, builder);
return builder.build();
} }
else { if (properties.getUser() != null && dataSource != null) {
configuration.dataSource(dataSource); DataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource)
.type(SimpleDriverDataSource.class);
applyCommonBuilderProperties(properties, builder);
return builder.build();
}
Assert.state(dataSource != null, "Flyway migration DataSource missing");
return dataSource;
}
private void applyCommonBuilderProperties(FlywayProperties properties, DataSourceBuilder<?> builder) {
builder.username(properties.getUser());
builder.password(properties.getPassword());
if (StringUtils.hasText(properties.getDriverClassName())) {
builder.driverClassName(properties.getDriverClassName());
} }
return configuration.getDataSource();
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
...@@ -279,11 +296,6 @@ public class FlywayAutoConfiguration { ...@@ -279,11 +296,6 @@ public class FlywayAutoConfiguration {
} }
} }
private String getProperty(Supplier<String> property, Supplier<String> defaultValue) {
String value = property.get();
return (value != null) ? value : defaultValue.get();
}
private boolean hasAtLeastOneLocation(ResourceLoader resourceLoader, Collection<String> locations) { private boolean hasAtLeastOneLocation(ResourceLoader resourceLoader, Collection<String> locations) {
for (String location : locations) { for (String location : locations) {
if (resourceLoader.getResource(normalizePrefix(location)).exists()) { if (resourceLoader.getResource(normalizePrefix(location)).exists()) {
......
...@@ -161,12 +161,6 @@ public class FlywayProperties { ...@@ -161,12 +161,6 @@ public class FlywayProperties {
*/ */
private String target; private String target;
/**
* JDBC url of the database to migrate. If not set, the primary configured data source
* is used.
*/
private String url;
/** /**
* Login user of the database to migrate. * Login user of the database to migrate.
*/ */
...@@ -177,6 +171,17 @@ public class FlywayProperties { ...@@ -177,6 +171,17 @@ public class FlywayProperties {
*/ */
private String password; private String password;
/**
* Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
*/
private String driverClassName;
/**
* JDBC url of the database to migrate. If not set, the primary configured data source
* is used.
*/
private String url;
/** /**
* SQL statements to execute to initialize a connection immediately after obtaining * SQL statements to execute to initialize a connection immediately after obtaining
* it. * it.
...@@ -538,18 +543,16 @@ public class FlywayProperties { ...@@ -538,18 +543,16 @@ public class FlywayProperties {
this.target = target; this.target = target;
} }
/**
* Return if a new datasource is being created.
* @return {@code true} if a new datasource is created
* @deprecated since 2.5.0 in favor of directly checking user and url.
*/
@Deprecated
public boolean isCreateDataSource() { public boolean isCreateDataSource() {
return this.url != null || this.user != null; return this.url != null || this.user != null;
} }
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() { public String getUser() {
return this.user; return this.user;
} }
...@@ -566,6 +569,22 @@ public class FlywayProperties { ...@@ -566,6 +569,22 @@ public class FlywayProperties {
this.password = password; this.password = password;
} }
public String getDriverClassName() {
return this.driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public List<String> getInitSqls() { public List<String> getInitSqls() {
return this.initSqls; return this.initSqls;
} }
......
...@@ -33,6 +33,7 @@ import org.springframework.core.io.DefaultResourceLoader; ...@@ -33,6 +33,7 @@ import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.config.SortedResourcesFactoryBean; import org.springframework.jdbc.config.SortedResourcesFactoryBean;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -185,10 +186,9 @@ public class DataSourceInitializer { ...@@ -185,10 +186,9 @@ public class DataSourceInitializer {
populator.addScript(resource); populator.addScript(resource);
} }
DataSource dataSource = this.dataSource; DataSource dataSource = this.dataSource;
if (StringUtils.hasText(username) && StringUtils.hasText(password)) { if (StringUtils.hasText(username) && dataSource != null) {
dataSource = DataSourceBuilder.create(this.properties.getClassLoader()) dataSource = DataSourceBuilder.derivedFrom(dataSource).type(SimpleDriverDataSource.class).username(username)
.driverClassName(this.properties.determineDriverClassName()).url(this.properties.determineUrl()) .password(password).build();
.username(username).password(password).build();
} }
DatabasePopulatorUtils.execute(populator, dataSource); DatabasePopulatorUtils.execute(populator, dataSource);
} }
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
package org.springframework.boot.autoconfigure.liquibase; package org.springframework.boot.autoconfigure.liquibase;
import java.util.function.Supplier;
import javax.sql.DataSource; import javax.sql.DataSource;
import liquibase.change.DatabaseChange; import liquibase.change.DatabaseChange;
...@@ -32,18 +30,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; ...@@ -32,18 +30,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseDataSourceCondition; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseDataSourceCondition;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer; import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
...@@ -77,7 +74,7 @@ public class LiquibaseAutoConfiguration { ...@@ -77,7 +74,7 @@ public class LiquibaseAutoConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(SpringLiquibase.class) @ConditionalOnMissingBean(SpringLiquibase.class)
@EnableConfigurationProperties({ DataSourceProperties.class, LiquibaseProperties.class }) @EnableConfigurationProperties(LiquibaseProperties.class)
public static class LiquibaseConfiguration { public static class LiquibaseConfiguration {
private final LiquibaseProperties properties; private final LiquibaseProperties properties;
...@@ -87,11 +84,10 @@ public class LiquibaseAutoConfiguration { ...@@ -87,11 +84,10 @@ public class LiquibaseAutoConfiguration {
} }
@Bean @Bean
public SpringLiquibase liquibase(DataSourceProperties dataSourceProperties, public SpringLiquibase liquibase(ObjectProvider<DataSource> dataSource,
ObjectProvider<DataSource> dataSource,
@LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource) { @LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource) {
SpringLiquibase liquibase = createSpringLiquibase(liquibaseDataSource.getIfAvailable(), SpringLiquibase liquibase = createSpringLiquibase(liquibaseDataSource.getIfAvailable(),
dataSource.getIfUnique(), dataSourceProperties); dataSource.getIfUnique());
liquibase.setChangeLog(this.properties.getChangeLog()); liquibase.setChangeLog(this.properties.getChangeLog());
liquibase.setClearCheckSums(this.properties.isClearChecksums()); liquibase.setClearCheckSums(this.properties.isClearChecksums());
liquibase.setContexts(this.properties.getContexts()); liquibase.setContexts(this.properties.getContexts());
...@@ -110,51 +106,43 @@ public class LiquibaseAutoConfiguration { ...@@ -110,51 +106,43 @@ public class LiquibaseAutoConfiguration {
return liquibase; return liquibase;
} }
private SpringLiquibase createSpringLiquibase(DataSource liquibaseDatasource, DataSource dataSource, private SpringLiquibase createSpringLiquibase(DataSource liquibaseDataSource, DataSource dataSource) {
DataSourceProperties dataSourceProperties) { LiquibaseProperties properties = this.properties;
DataSource liquibaseDataSource = getDataSource(liquibaseDatasource, dataSource); DataSource migrationDataSource = getMigrationDataSource(liquibaseDataSource, dataSource, properties);
if (liquibaseDataSource != null) { SpringLiquibase liquibase = (migrationDataSource == liquibaseDataSource
SpringLiquibase liquibase = new SpringLiquibase(); || migrationDataSource == dataSource) ? new SpringLiquibase()
liquibase.setDataSource(liquibaseDataSource); : new DataSourceClosingSpringLiquibase();
return liquibase; liquibase.setDataSource(migrationDataSource);
}
SpringLiquibase liquibase = new DataSourceClosingSpringLiquibase();
liquibase.setDataSource(createNewDataSource(dataSourceProperties));
return liquibase; return liquibase;
} }
private DataSource getDataSource(DataSource liquibaseDataSource, DataSource dataSource) { private DataSource getMigrationDataSource(DataSource liquibaseDataSource, DataSource dataSource,
LiquibaseProperties properties) {
if (liquibaseDataSource != null) { if (liquibaseDataSource != null) {
return liquibaseDataSource; return liquibaseDataSource;
} }
if (this.properties.getUrl() == null && this.properties.getUser() == null) { if (properties.getUrl() != null) {
return dataSource; DataSourceBuilder<?> builder = DataSourceBuilder.create().type(SimpleDriverDataSource.class);
builder.url(properties.getUrl());
applyCommonBuilderProperties(properties, builder);
return builder.build();
} }
return null; if (properties.getUser() != null && dataSource != null) {
} DataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource)
.type(SimpleDriverDataSource.class);
private DataSource createNewDataSource(DataSourceProperties dataSourceProperties) { applyCommonBuilderProperties(properties, builder);
String url = getProperty(this.properties::getUrl, dataSourceProperties::determineUrl); return builder.build();
String user = getProperty(this.properties::getUser, dataSourceProperties::determineUsername);
String password = getProperty(this.properties::getPassword, dataSourceProperties::determinePassword);
String driverClassName = determineDriverClassName(dataSourceProperties, url);
return DataSourceBuilder.create().type(SimpleDriverDataSource.class).url(url).username(user)
.password(password).driverClassName(driverClassName).build();
}
private String determineDriverClassName(DataSourceProperties dataSourceProperties, String url) {
if (StringUtils.hasText(this.properties.getDriverClassName())) {
return this.properties.getDriverClassName();
} }
if (StringUtils.hasText(dataSourceProperties.getDriverClassName())) { Assert.state(dataSource != null, "Liquibase migration DataSource missing");
return dataSourceProperties.getDriverClassName(); return dataSource;
}
return StringUtils.hasText(url) ? DatabaseDriver.fromJdbcUrl(url).getDriverClassName() : null;
} }
private String getProperty(Supplier<String> property, Supplier<String> defaultValue) { private void applyCommonBuilderProperties(LiquibaseProperties properties, DataSourceBuilder<?> builder) {
String value = property.get(); builder.username(properties.getUser());
return (value != null) ? value : defaultValue.get(); builder.password(properties.getPassword());
if (StringUtils.hasText(properties.getDriverClassName())) {
builder.driverClassName(properties.getDriverClassName());
}
} }
} }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.flyway; package org.springframework.boot.autoconfigure.flyway;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -42,7 +44,9 @@ import org.mockito.InOrder; ...@@ -42,7 +44,9 @@ import org.mockito.InOrder;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.SchemaManagement; import org.springframework.boot.jdbc.SchemaManagement;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
...@@ -62,6 +66,10 @@ import org.springframework.jdbc.core.JdbcOperations; ...@@ -62,6 +66,10 @@ import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -128,25 +136,42 @@ class FlywayAutoConfigurationTests { ...@@ -128,25 +136,42 @@ class FlywayAutoConfigurationTests {
} }
@Test @Test
void createDataSourceFallbackToEmbeddedProperties() { void createDataSourceDoesNotFallbackToEmbeddedProperties() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.flyway.url:jdbc:hsqldb:mem:flywaytest").run((context) -> { .withPropertyValues("spring.flyway.url:jdbc:hsqldb:mem:flywaytest").run((context) -> {
assertThat(context).hasSingleBean(Flyway.class); assertThat(context).hasSingleBean(Flyway.class);
DataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource(); DataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource();
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
assertThat(dataSource).hasFieldOrPropertyWithValue("user", "sa"); assertThat(dataSource).hasFieldOrPropertyWithValue("username", null);
assertThat(dataSource).hasFieldOrPropertyWithValue("password", ""); assertThat(dataSource).hasFieldOrPropertyWithValue("password", "");
}); });
} }
@Test @Test
void createDataSourceWithUserAndFallbackToEmbeddedProperties() { void createDataSourceWithUserAndFallbackToEmbeddedProperties() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(PropertiesBackedH2DataSourceConfiguration.class)
.withPropertyValues("spring.flyway.user:sa").run((context) -> { .withPropertyValues("spring.flyway.user:test", "spring.flyway.password:secret").run((context) -> {
assertThat(context).hasSingleBean(Flyway.class); assertThat(context).hasSingleBean(Flyway.class);
DataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource(); DataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource();
assertThat(dataSource).isNotNull(); assertThat(dataSource).isNotNull();
assertThat(dataSource).extracting("url").asString().startsWith("jdbc:h2:mem:"); assertThat(dataSource).extracting("url").asString().startsWith("jdbc:h2:mem:");
assertThat(dataSource).extracting("username").asString().isEqualTo("test");
});
}
@Test
void createDataSourceWithUserAndCustomEmbeddedProperties() {
this.contextRunner.withUserConfiguration(CustomBackedH2DataSourceConfiguration.class)
.withPropertyValues("spring.flyway.user:test", "spring.flyway.password:secret").run((context) -> {
assertThat(context).hasSingleBean(Flyway.class);
String expectedName = context.getBean(CustomBackedH2DataSourceConfiguration.class).name;
String propertiesName = context.getBean(DataSourceProperties.class).determineDatabaseName();
assertThat(expectedName).isNotEqualTo(propertiesName);
DataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource();
assertThat(dataSource).isNotNull();
assertThat(dataSource).extracting("url").asString().startsWith("jdbc:h2:mem:")
.contains(expectedName);
assertThat(dataSource).extracting("username").asString().isEqualTo("test");
}); });
} }
...@@ -239,6 +264,20 @@ class FlywayAutoConfigurationTests { ...@@ -239,6 +264,20 @@ class FlywayAutoConfigurationTests {
}); });
} }
@Test
void overrideDataSourceAndDriverClassName() {
String jdbcUrl = "jdbc:hsqldb:mem:flyway" + UUID.randomUUID();
String driverClassName = "org.hsqldb.jdbcDriver";
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).withPropertyValues(
"spring.flyway.url:" + jdbcUrl, "spring.flyway.driver-class-name:" + driverClassName).run((context) -> {
Flyway flyway = context.getBean(Flyway.class);
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) flyway.getConfiguration()
.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);
assertThat(dataSource.getDriver().getClass().getName()).isEqualTo(driverClassName);
});
}
@Test @Test
void changeLogDoesNotExist() { void changeLogDoesNotExist() {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
...@@ -842,6 +881,51 @@ class FlywayAutoConfigurationTests { ...@@ -842,6 +881,51 @@ class FlywayAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(DataSourceProperties.class)
abstract static class AbstractUserH2DataSourceConfiguration {
@Bean(destroyMethod = "shutdown")
EmbeddedDatabase dataSource(DataSourceProperties properties) throws SQLException {
EmbeddedDatabase database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
.setName(getDatabaseName(properties)).build();
insertUser(database);
return database;
}
protected abstract String getDatabaseName(DataSourceProperties properties);
private void insertUser(EmbeddedDatabase database) throws SQLException {
try (Connection connection = database.getConnection()) {
connection.prepareStatement("CREATE USER test password 'secret'").execute();
connection.prepareStatement("ALTER USER test ADMIN TRUE").execute();
}
}
}
@Configuration(proxyBeanMethods = false)
static class PropertiesBackedH2DataSourceConfiguration extends AbstractUserH2DataSourceConfiguration {
@Override
protected String getDatabaseName(DataSourceProperties properties) {
return properties.determineDatabaseName();
}
}
@Configuration(proxyBeanMethods = false)
static class CustomBackedH2DataSourceConfiguration extends AbstractUserH2DataSourceConfiguration {
private final String name = UUID.randomUUID().toString();
@Override
protected String getDatabaseName(DataSourceProperties properties) {
return this.name;
}
}
static final class CustomClassLoader extends ClassLoader { static final class CustomClassLoader extends ClassLoader {
private CustomClassLoader(ClassLoader parent) { private CustomClassLoader(ClassLoader parent) {
......
...@@ -100,7 +100,8 @@ class FlywayPropertiesTests { ...@@ -100,7 +100,8 @@ class FlywayPropertiesTests {
Map<String, PropertyDescriptor> configuration = indexProperties( Map<String, PropertyDescriptor> configuration = indexProperties(
PropertyAccessorFactory.forBeanPropertyAccess(new ClassicConfiguration())); PropertyAccessorFactory.forBeanPropertyAccess(new ClassicConfiguration()));
// Properties specific settings // Properties specific settings
ignoreProperties(properties, "url", "user", "password", "enabled", "checkLocation", "createDataSource"); ignoreProperties(properties, "url", "driverClassName", "user", "password", "enabled", "checkLocation",
"createDataSource");
// High level object we can't set with properties // High level object we can't set with properties
ignoreProperties(configuration, "callbacks", "classLoader", "dataSource", "javaMigrations", ignoreProperties(configuration, "callbacks", "classLoader", "dataSource", "javaMigrations",
"javaMigrationClassProvider", "resourceProvider", "resolvers"); "javaMigrationClassProvider", "resourceProvider", "resolvers");
......
...@@ -92,6 +92,17 @@ class DataSourceInitializationIntegrationTests { ...@@ -92,6 +92,17 @@ class DataSourceInitializationIntegrationTests {
}); });
} }
@Test
void initializationWithUsernameAndPasswordAppliesToCustomDataSource() {
this.contextRunner.withUserConfiguration(OneDataSource.class)
.withPropertyValues("spring.datasource.initialization-mode:always",
"spring.datasource.schema-username=test", "spring.datasource.schema-password=secret")
.run((context) -> {
assertThat(context).hasSingleBean(DataSource.class);
assertDataSourceIsInitialized(context.getBean(DataSource.class));
});
}
private void assertDataSourceIsInitialized(DataSource dataSource) { private void assertDataSourceIsInitialized(DataSource dataSource) {
JdbcOperations template = new JdbcTemplate(dataSource); JdbcOperations template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject("SELECT COUNT(*) from BAR", Integer.class)).isEqualTo(1); assertThat(template.queryForObject("SELECT COUNT(*) from BAR", Integer.class)).isEqualTo(1);
...@@ -286,7 +297,7 @@ class DataSourceInitializationIntegrationTests { ...@@ -286,7 +297,7 @@ class DataSourceInitializationIntegrationTests {
@Bean @Bean
DataSource oneDataSource() { DataSource oneDataSource() {
return new TestDataSource(); return new TestDataSource(true);
} }
} }
...@@ -296,7 +307,7 @@ class DataSourceInitializationIntegrationTests { ...@@ -296,7 +307,7 @@ class DataSourceInitializationIntegrationTests {
@Bean @Bean
DataSource twoDataSource() { DataSource twoDataSource() {
return new TestDataSource(); return new TestDataSource(true);
} }
} }
......
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -32,12 +32,12 @@ class MultiDataSourceConfiguration { ...@@ -32,12 +32,12 @@ class MultiDataSourceConfiguration {
@Bean @Bean
DataSource test1DataSource() { DataSource test1DataSource() {
return new TestDataSource("test1"); return new TestDataSource("test1", false);
} }
@Bean @Bean
DataSource test2DataSource() { DataSource test2DataSource() {
return new TestDataSource("test2"); return new TestDataSource("test2", false);
} }
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -34,12 +34,12 @@ class MultiDataSourceUsingPrimaryConfiguration { ...@@ -34,12 +34,12 @@ class MultiDataSourceUsingPrimaryConfiguration {
@Bean @Bean
@Primary @Primary
DataSource test1DataSource() { DataSource test1DataSource() {
return new TestDataSource("test1"); return new TestDataSource("test1", false);
} }
@Bean @Bean
DataSource test2DataSource() { DataSource test2DataSource() {
return new TestDataSource("test2"); return new TestDataSource("test2", false);
} }
} }
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,10 +16,14 @@ ...@@ -16,10 +16,14 @@
package org.springframework.boot.autoconfigure.jdbc; package org.springframework.boot.autoconfigure.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
/** /**
* {@link BasicDataSource} used for testing. * {@link BasicDataSource} used for testing.
* *
...@@ -27,23 +31,45 @@ import org.apache.commons.dbcp2.BasicDataSource; ...@@ -27,23 +31,45 @@ import org.apache.commons.dbcp2.BasicDataSource;
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
public class TestDataSource extends BasicDataSource { public class TestDataSource extends SimpleDriverDataSource {
/**
* Create an in-memory database with a random name.
*/
public TestDataSource() {
this(false);
}
/**
* Create an in-memory database with a random name.
* @param addTestUser if a test user should be added
*/
public TestDataSource(boolean addTestUser) {
this(UUID.randomUUID().toString(), addTestUser);
}
/** /**
* Create an in-memory database with the specified name. * Create an in-memory database with the specified name.
* @param name the name of the database * @param name the name of the database
* @param addTestUser if a test user should be added
*/ */
public TestDataSource(String name) { public TestDataSource(String name, boolean addTestUser) {
setDriverClassName("org.hsqldb.jdbcDriver"); setDriverClass(org.hsqldb.jdbc.JDBCDriver.class);
setUrl("jdbc:hsqldb:mem:" + name); setUrl("jdbc:hsqldb:mem:" + name);
setUsername("sa"); setUsername("sa");
setupDatabase(addTestUser);
setUrl(getUrl() + ";create=false");
} }
/** private void setupDatabase(boolean addTestUser) {
* Create an in-memory database with a random name. try (Connection connection = getConnection()) {
*/ if (addTestUser) {
public TestDataSource() { connection.prepareStatement("CREATE USER \"test\" password \"secret\" ADMIN").execute();
this(UUID.randomUUID().toString()); }
}
catch (SQLException ex) {
throw new IllegalStateException(ex);
}
} }
} }
...@@ -20,7 +20,10 @@ import java.io.File; ...@@ -20,7 +20,10 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.sql.DataSource; import javax.sql.DataSource;
...@@ -50,6 +53,9 @@ import org.springframework.context.annotation.Configuration; ...@@ -50,6 +53,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -82,11 +88,11 @@ class LiquibaseAutoConfigurationTests { ...@@ -82,11 +88,11 @@ class LiquibaseAutoConfigurationTests {
@Test @Test
void createsDataSourceWithNoDataSourceBeanAndLiquibaseUrl() { void createsDataSourceWithNoDataSourceBeanAndLiquibaseUrl() {
this.contextRunner.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:liquibase") String jdbcUrl = "jdbc:hsqldb:mem:liquibase" + UUID.randomUUID();
.run(assertLiquibase((liquibase) -> { this.contextRunner.withPropertyValues("spring.liquibase.url:" + jdbcUrl).run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource(); SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo("jdbc:hsqldb:mem:liquibase"); assertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);
})); }));
} }
@Test @Test
...@@ -191,18 +197,18 @@ class LiquibaseAutoConfigurationTests { ...@@ -191,18 +197,18 @@ class LiquibaseAutoConfigurationTests {
@Test @Test
void overrideDataSource() { void overrideDataSource() {
String jdbcUrl = "jdbc:hsqldb:mem:liquibase" + UUID.randomUUID();
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:liquibase") .withPropertyValues("spring.liquibase.url:" + jdbcUrl).run(assertLiquibase((liquibase) -> {
.run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource(); SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo("jdbc:hsqldb:mem:liquibase"); assertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);
assertThat(dataSource.getDriver().getClass().getName()).isEqualTo("org.hsqldb.jdbc.JDBCDriver"); assertThat(dataSource.getDriver().getClass().getName()).isEqualTo("org.hsqldb.jdbc.JDBCDriver");
})); }));
} }
@Test @Test
void overrideDataSourceAndDriverClassName() { void overrideDataSourceAndDriverClassName() {
String jdbcUrl = "jdbc:hsqldb:mem:liquibase"; String jdbcUrl = "jdbc:hsqldb:mem:liquibase" + UUID.randomUUID();
String driverClassName = "org.hsqldb.jdbcDriver"; String driverClassName = "org.hsqldb.jdbcDriver";
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.liquibase.url:" + jdbcUrl, .withPropertyValues("spring.liquibase.url:" + jdbcUrl,
...@@ -215,40 +221,39 @@ class LiquibaseAutoConfigurationTests { ...@@ -215,40 +221,39 @@ class LiquibaseAutoConfigurationTests {
} }
@Test @Test
void overrideDataSourceWithFallbackDriverClassName() { void overrideUser() {
String jdbcUrl = "jdbc:hsqldb:mem:liquibase"; String databaseName = "normal" + UUID.randomUUID();
String driverClassName = "org.hsqldb.jdbcDriver";
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.liquibase.url:" + jdbcUrl, .withPropertyValues("spring.datasource.generate-unique-name:false",
"spring.datasource.driver-class-name:" + driverClassName) "spring.datasource.name:" + databaseName, "spring.datasource.username:not-sa",
"spring.liquibase.user:sa")
.run(assertLiquibase((liquibase) -> { .run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource(); SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo(jdbcUrl); assertThat(dataSource.getUrl()).contains("jdbc:h2:mem:" + databaseName);
assertThat(dataSource.getDriver().getClass().getName()).isEqualTo(driverClassName); assertThat(dataSource.getUsername()).isEqualTo("sa");
})); }));
} }
@Test @Test
void overrideUser() { void overrideUserWhenCustom() {
String jdbcUrl = "jdbc:hsqldb:mem:normal"; this.contextRunner.withUserConfiguration(CustomDataSourceConfiguration.class)
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) .withPropertyValues("spring.liquibase.user:test", "spring.liquibase.password:secret").run((context) -> {
.withPropertyValues("spring.datasource.url:" + jdbcUrl, "spring.datasource.username:not-sa", String expectedName = context.getBean(CustomDataSourceConfiguration.class).name;
"spring.liquibase.user:sa") SpringLiquibase liquibase = context.getBean(SpringLiquibase.class);
.run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource(); SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUrl()).isEqualTo(jdbcUrl); assertThat(dataSource.getUrl()).contains(expectedName);
assertThat(dataSource.getUsername()).isEqualTo("sa"); assertThat(dataSource.getUsername()).isEqualTo("test");
})); });
} }
@Test @Test
void overrideDataSourceAndFallbackToEmbeddedProperties() { void createDataSourceDoesNotFallbackToEmbeddedProperties() {
String jdbcUrl = "jdbc:hsqldb:mem:liquibase" + UUID.randomUUID();
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.liquibase.url:jdbc:hsqldb:mem:liquibase") .withPropertyValues("spring.liquibase.url:" + jdbcUrl).run(assertLiquibase((liquibase) -> {
.run(assertLiquibase((liquibase) -> {
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource(); SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
assertThat(dataSource.getUsername()).isEqualTo("sa"); assertThat(dataSource.getUsername()).isNull();
assertThat(dataSource.getPassword()).isEqualTo(""); assertThat(dataSource.getPassword()).isNull();
})); }));
} }
...@@ -404,13 +409,14 @@ class LiquibaseAutoConfigurationTests { ...@@ -404,13 +409,14 @@ class LiquibaseAutoConfigurationTests {
@Bean @Bean
@Primary @Primary
DataSource normalDataSource() { DataSource normalDataSource() {
return DataSourceBuilder.create().url("jdbc:hsqldb:mem:normal").username("sa").build(); return DataSourceBuilder.create().url("jdbc:hsqldb:mem:normal" + UUID.randomUUID()).username("sa").build();
} }
@LiquibaseDataSource @LiquibaseDataSource
@Bean @Bean
DataSource liquibaseDataSource() { DataSource liquibaseDataSource() {
return DataSourceBuilder.create().url("jdbc:hsqldb:mem:liquibasetest").username("sa").build(); return DataSourceBuilder.create().url("jdbc:hsqldb:mem:liquibasetest" + UUID.randomUUID()).username("sa")
.build();
} }
} }
...@@ -429,4 +435,47 @@ class LiquibaseAutoConfigurationTests { ...@@ -429,4 +435,47 @@ class LiquibaseAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false)
static class CustomDataSourceConfiguration {
private String name = UUID.randomUUID().toString();
@Bean(destroyMethod = "shutdown")
EmbeddedDatabase dataSource() throws SQLException {
EmbeddedDatabase database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
.setName(this.name).build();
insertUser(database);
return database;
}
private void insertUser(EmbeddedDatabase database) throws SQLException {
try (Connection connection = database.getConnection()) {
connection.prepareStatement("CREATE USER test password 'secret'").execute();
connection.prepareStatement("ALTER USER test ADMIN TRUE").execute();
}
}
}
@Configuration(proxyBeanMethods = false)
static class CustomDriverConfiguration {
private String name = UUID.randomUUID().toString();
@Bean
SimpleDriverDataSource dataSource() throws SQLException {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(CustomH2Driver.class);
dataSource.setUrl(String.format("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false", this.name));
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}
static class CustomH2Driver extends org.h2.Driver {
}
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<allow pkg=".*" regex="true" /> <allow pkg=".*" regex="true" />
<subpackage name="autoconfigure"> <subpackage name="autoconfigure">
<disallow class="org.springframework.boot.autoconfigure.jdbc.DataSourceProperties"/>
<subpackage name="web"> <subpackage name="web">
<allow pkg="org.springframework.boot.web.server" /> <allow pkg="org.springframework.boot.web.server" />
<allow pkg="org.springframework.boot.web.servlet.server" /> <allow pkg="org.springframework.boot.web.servlet.server" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment