From c406dda18160a29649eef6bbb73f3c93674f4028 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 12 Jul 2021 19:35:15 +0100 Subject: [PATCH] Deprecate AbstractDataSourceInitializer Closes gh-27206 Co-authored-by: Phillip Webb --- .../batch/BatchAutoConfiguration.java | 13 +- .../batch/BatchDataSourceInitializer.java | 21 ++- ...chDataSourceScriptDatabaseInitializer.java | 79 ++++++++++++ .../autoconfigure/batch/BatchProperties.java | 12 +- .../IntegrationAutoConfiguration.java | 11 +- .../IntegrationDataSourceInitializer.java | 23 +++- ...onDataSourceScriptDatabaseInitializer.java | 76 +++++++++++ .../integration/IntegrationProperties.java | 8 +- .../jdbc/DataSourceAutoConfiguration.java | 3 + ...DataSourceInitializationConfiguration.java | 16 +-- .../jdbc/DataSourceProperties.java | 7 +- .../quartz/QuartzAutoConfiguration.java | 11 +- .../quartz/QuartzDataSourceInitializer.java | 21 ++- ...tzDataSourceScriptDatabaseInitializer.java | 81 ++++++++++++ .../quartz/QuartzProperties.java | 10 +- .../SchedulerFactoryBeanCustomizer.java | 4 +- .../r2dbc/R2dbcAutoConfiguration.java | 3 +- .../session/JdbcSessionConfiguration.java | 13 +- .../JdbcSessionDataSourceInitializer.java | 23 +++- ...onDataSourceScriptDatabaseInitializer.java | 77 +++++++++++ .../session/JdbcSessionProperties.java | 10 +- ...DataSourceInitializationConfiguration.java | 14 +- .../R2dbcInitializationConfiguration.java | 11 +- .../sql/init/SettingsCreator.java | 1 - ...qlDataSourceScriptDatabaseInitializer.java | 66 ++++++++++ .../SqlInitializationAutoConfiguration.java | 3 - .../SqlR2dbcScriptDatabaseInitializer.java | 69 ++++++++++ .../batch/BatchAutoConfigurationTests.java | 80 +++++++++++- ...BatchAutoConfigurationWithoutJpaTests.java | 4 +- .../JobLauncherApplicationRunnerTests.java | 10 +- .../IntegrationAutoConfigurationTests.java | 81 +++++++++++- .../quartz/QuartzAutoConfigurationTests.java | 76 ++++++++++- .../QuartzDataSourceInitializerTests.java | 3 +- .../SessionAutoConfigurationJdbcTests.java | 87 ++++++++++++- ...lInitializationAutoConfigurationTests.java | 48 ++++++- .../jdbc/AbstractDataSourceInitializer.java | 6 +- ...nitializerDatabaseInitializerDetector.java | 1 + .../jdbc/DataSourceInitializationMode.java | 6 +- .../boot/jdbc/DatabaseDriver.java | 21 +++ .../DataSourceScriptDatabaseInitializer.java | 2 +- ...formPlaceholderDatabaseDriverResolver.java | 122 ++++++++++++++++++ ...itializerDependencyConfigurationTests.java | 1 + ...laceholderDatabaseDriverResolverTests.java | 96 ++++++++++++++ 43 files changed, 1198 insertions(+), 132 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlDataSourceScriptDatabaseInitializer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlR2dbcScriptDatabaseInitializer.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolver.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolverTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java index ce670528d4..e13959825c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java @@ -39,7 +39,6 @@ import org.springframework.boot.sql.init.dependency.DatabaseInitializationDepend import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.datasource.init.DatabasePopulator; import org.springframework.util.StringUtils; @@ -107,12 +106,12 @@ public class BatchAutoConfiguration { static class DataSourceInitializerConfiguration { @Bean - @ConditionalOnMissingBean - BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource, - @BatchDataSource ObjectProvider batchDataSource, ResourceLoader resourceLoader, - BatchProperties properties) { - return new BatchDataSourceInitializer(batchDataSource.getIfAvailable(() -> dataSource), resourceLoader, - properties); + @SuppressWarnings("deprecation") + @ConditionalOnMissingBean({ BatchDataSourceScriptDatabaseInitializer.class, BatchDataSourceInitializer.class }) + BatchDataSourceScriptDatabaseInitializer batchDataSourceInitializer(DataSource dataSource, + @BatchDataSource ObjectProvider batchDataSource, BatchProperties properties) { + return new BatchDataSourceScriptDatabaseInitializer(batchDataSource.getIfAvailable(() -> dataSource), + properties.getJdbc()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceInitializer.java index b642fe2f44..e9bff2fb62 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceInitializer.java @@ -19,8 +19,7 @@ package org.springframework.boot.autoconfigure.batch; import javax.sql.DataSource; import org.springframework.boot.autoconfigure.batch.BatchProperties.Jdbc; -import org.springframework.boot.jdbc.AbstractDataSourceInitializer; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; @@ -30,8 +29,11 @@ import org.springframework.util.Assert; * @author Dave Syer * @author Vedran Pavic * @since 1.0.0 + * @deprecated since 2.6.0 for removal in 2.8.0 in favor of + * {@link BatchDataSourceScriptDatabaseInitializer} */ -public class BatchDataSourceInitializer extends AbstractDataSourceInitializer { +@Deprecated +public class BatchDataSourceInitializer extends org.springframework.boot.jdbc.AbstractDataSourceInitializer { private final Jdbc jdbcProperties; @@ -43,8 +45,17 @@ public class BatchDataSourceInitializer extends AbstractDataSourceInitializer { } @Override - protected DataSourceInitializationMode getMode() { - return this.jdbcProperties.getInitializeSchema(); + protected org.springframework.boot.jdbc.DataSourceInitializationMode getMode() { + DatabaseInitializationMode mode = this.jdbcProperties.getInitializeSchema(); + switch (mode) { + case ALWAYS: + return org.springframework.boot.jdbc.DataSourceInitializationMode.ALWAYS; + case EMBEDDED: + return org.springframework.boot.jdbc.DataSourceInitializationMode.EMBEDDED; + case NEVER: + default: + return org.springframework.boot.jdbc.DataSourceInitializationMode.NEVER; + } } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java new file mode 100644 index 0000000000..dbd4b1ad53 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.batch; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; + +/** + * {@link DataSourceScriptDatabaseInitializer} for the Spring Batch database. May be + * registered as a bean to override auto-configuration. + * + * @author Dave Syer + * @author Vedran Pavic + * @author Andy Wilkinson + * @author Phillip Webb + * @since 2.6.0 + */ +public class BatchDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { + + /** + * Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Spring Batch data source + * @param properties the Spring Batch JDBC properties + * @see #getSettings + */ + public BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, BatchProperties.Jdbc properties) { + this(dataSource, getSettings(dataSource, properties)); + } + + /** + * Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Spring Batch data source + * @param settings the database initialization settings + * @see #getSettings + */ + public BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { + super(dataSource, settings); + } + + /** + * Adapts {@link BatchProperties.Jdbc Spring Batch JDBC properties} to + * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} + * placeholders. + * @param dataSource the Spring Batch data source + * @param properties batch JDBC properties + * @return a new {@link DatabaseInitializationSettings} instance + * @see #BatchDataSourceScriptDatabaseInitializer(DataSource, + * DatabaseInitializationSettings) + */ + public static DatabaseInitializationSettings getSettings(DataSource dataSource, BatchProperties.Jdbc properties) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.ORACLE, "oracle10g"); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MARIADB, "mysql"); + settings.setSchemaLocations(platformResolver.resolveAll(dataSource, properties.getSchema())); + settings.setMode(properties.getInitializeSchema()); + settings.setContinueOnError(true); + return settings; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java index 637cd63cf7..2b63db616e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java @@ -18,7 +18,7 @@ package org.springframework.boot.autoconfigure.batch; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; /** * Configuration properties for Spring Batch. @@ -77,12 +77,12 @@ public class BatchProperties { */ @Deprecated @DeprecatedConfigurationProperty(replacement = "spring.batch.jdbc.initialize-schema") - public DataSourceInitializationMode getInitializeSchema() { + public DatabaseInitializationMode getInitializeSchema() { return this.jdbc.getInitializeSchema(); } @Deprecated - public void setInitializeSchema(DataSourceInitializationMode initializeSchema) { + public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { this.jdbc.setInitializeSchema(initializeSchema); } @@ -130,7 +130,7 @@ public class BatchProperties { /** * Database schema initialization mode. */ - private DataSourceInitializationMode initializeSchema = DataSourceInitializationMode.EMBEDDED; + private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; public String getSchema() { return this.schema; @@ -148,11 +148,11 @@ public class BatchProperties { this.tablePrefix = tablePrefix; } - public DataSourceInitializationMode getInitializeSchema() { + public DatabaseInitializationMode getInitializeSchema() { return this.initializeSchema; } - public void setInitializeSchema(DataSourceInitializationMode initializeSchema) { + public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { this.initializeSchema = initializeSchema; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 456e9b40a8..71dfd778e1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -43,7 +43,6 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; import org.springframework.integration.config.EnableIntegration; import org.springframework.integration.config.EnableIntegrationManagement; import org.springframework.integration.config.IntegrationManagementConfigurer; @@ -189,10 +188,12 @@ public class IntegrationAutoConfiguration { protected static class IntegrationJdbcConfiguration { @Bean - @ConditionalOnMissingBean - public IntegrationDataSourceInitializer integrationDataSourceInitializer(DataSource dataSource, - ResourceLoader resourceLoader, IntegrationProperties properties) { - return new IntegrationDataSourceInitializer(dataSource, resourceLoader, properties); + @SuppressWarnings("deprecation") + @ConditionalOnMissingBean({ IntegrationDataSourceScriptDatabaseInitializer.class, + IntegrationDataSourceInitializer.class }) + public IntegrationDataSourceScriptDatabaseInitializer integrationDataSourceInitializer(DataSource dataSource, + IntegrationProperties properties) { + return new IntegrationDataSourceScriptDatabaseInitializer(dataSource, properties.getJdbc()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceInitializer.java index b11f56bfb8..24d5356ce0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceInitializer.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -18,8 +18,7 @@ package org.springframework.boot.autoconfigure.integration; import javax.sql.DataSource; -import org.springframework.boot.jdbc.AbstractDataSourceInitializer; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; @@ -28,8 +27,11 @@ import org.springframework.util.Assert; * * @author Vedran Pavic * @since 2.0.0 + * @deprecated since 2.6.0 for removal in 2.8.0 in favor of + * {@link IntegrationDataSourceScriptDatabaseInitializer} */ -public class IntegrationDataSourceInitializer extends AbstractDataSourceInitializer { +@Deprecated +public class IntegrationDataSourceInitializer extends org.springframework.boot.jdbc.AbstractDataSourceInitializer { private final IntegrationProperties.Jdbc properties; @@ -41,8 +43,17 @@ public class IntegrationDataSourceInitializer extends AbstractDataSourceInitiali } @Override - protected DataSourceInitializationMode getMode() { - return this.properties.getInitializeSchema(); + protected org.springframework.boot.jdbc.DataSourceInitializationMode getMode() { + DatabaseInitializationMode mode = this.properties.getInitializeSchema(); + switch (mode) { + case ALWAYS: + return org.springframework.boot.jdbc.DataSourceInitializationMode.ALWAYS; + case EMBEDDED: + return org.springframework.boot.jdbc.DataSourceInitializationMode.EMBEDDED; + case NEVER: + default: + return org.springframework.boot.jdbc.DataSourceInitializationMode.NEVER; + } } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java new file mode 100644 index 0000000000..2b15c6b3e8 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.integration; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; + +/** + * {@link DataSourceScriptDatabaseInitializer} for the Spring Integration database. May be + * registered as a bean to override auto-configuration. + * + * @author Vedran Pavic + * @author Andy Wilkinson + * @since 2.6.0 + */ +public class IntegrationDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { + + /** + * Create a new {@link IntegrationDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Spring Integration data source + * @param properties the Spring Integration JDBC properties + * @see #getSettings + */ + public IntegrationDataSourceScriptDatabaseInitializer(DataSource dataSource, + IntegrationProperties.Jdbc properties) { + this(dataSource, getSettings(dataSource, properties)); + } + + /** + * Create a new {@link IntegrationDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Spring Integration data source + * @param settings the database initialization settings + * @see #getSettings + */ + public IntegrationDataSourceScriptDatabaseInitializer(DataSource dataSource, + DatabaseInitializationSettings settings) { + super(dataSource, settings); + } + + /** + * Adapts {@link IntegrationProperties.Jdbc Spring Integration JDBC properties} to + * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} + * placeholders. + * @param dataSource the Spring Integration data source + * @param properties the Spring Integration JDBC properties + * @return a new {@link DatabaseInitializationSettings} instance + * @see #IntegrationDataSourceScriptDatabaseInitializer(DataSource, + * DatabaseInitializationSettings) + */ + static DatabaseInitializationSettings getSettings(DataSource dataSource, IntegrationProperties.Jdbc properties) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); + settings.setSchemaLocations(platformResolver.resolveAll(dataSource, properties.getSchema())); + settings.setMode(properties.getInitializeSchema()); + settings.setContinueOnError(true); + return settings; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java index b5e10e9c20..ed4109a197 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java @@ -21,7 +21,7 @@ import java.util.ArrayList; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; /** * Configuration properties for Spring Integration. @@ -199,7 +199,7 @@ public class IntegrationProperties { /** * Database schema initialization mode. */ - private DataSourceInitializationMode initializeSchema = DataSourceInitializationMode.EMBEDDED; + private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; public String getSchema() { return this.schema; @@ -209,11 +209,11 @@ public class IntegrationProperties { this.schema = schema; } - public DataSourceInitializationMode getInitializeSchema() { + public DatabaseInitializationMode getInitializeSchema() { return this.initializeSchema; } - public void setInitializeSchema(DataSourceInitializationMode initializeSchema) { + public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { this.initializeSchema = initializeSchema; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java index 6dbdece9c2..742681d7f1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jdbc; import javax.sql.DataSource; import javax.sql.XADataSource; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; import org.springframework.boot.autoconfigure.condition.ConditionMessage; @@ -28,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration; +import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; @@ -54,6 +56,7 @@ import org.springframework.util.StringUtils; @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory") +@AutoConfigureBefore(SqlInitializationAutoConfiguration.class) @EnableConfigurationProperties(DataSourceProperties.class) @Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java index 73059859fc..780187234f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializationConfiguration.java @@ -37,8 +37,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandi import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfiguration.InitializationSpecificCredentialsDataSourceInitializationConfiguration.DifferentCredentialsCondition; import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfiguration.SharedCredentialsDataSourceInitializationConfiguration.DataSourceInitializationCondition; +import org.springframework.boot.autoconfigure.sql.init.SqlDataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.boot.sql.init.DatabaseInitializationSettings; @@ -78,7 +78,7 @@ class DataSourceInitializationConfiguration { return fallbackLocations; } - private static DatabaseInitializationMode mapMode(DataSourceInitializationMode mode) { + private static DatabaseInitializationMode mapMode(org.springframework.boot.jdbc.DataSourceInitializationMode mode) { switch (mode) { case ALWAYS: return DatabaseInitializationMode.ALWAYS; @@ -100,7 +100,7 @@ class DataSourceInitializationConfiguration { static class InitializationSpecificCredentialsDataSourceInitializationConfiguration { @Bean - DataSourceScriptDatabaseInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, + SqlDataSourceScriptDatabaseInitializer ddlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, DataSourceProperties properties) { DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(scriptLocations(properties.getSchema(), "schema", properties.getPlatform())); @@ -110,12 +110,12 @@ class DataSourceInitializationConfiguration { settings.setMode(mapMode(properties.getInitializationMode())); DataSource initializationDataSource = determineDataSource(dataSource::getObject, properties.getSchemaUsername(), properties.getSchemaPassword()); - return new DataSourceScriptDatabaseInitializer(initializationDataSource, settings); + return new SqlDataSourceScriptDatabaseInitializer(initializationDataSource, settings); } @Bean @DependsOn("ddlOnlyScriptDataSourceInitializer") - DataSourceScriptDatabaseInitializer dmlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, + SqlDataSourceScriptDatabaseInitializer dmlOnlyScriptDataSourceInitializer(ObjectProvider dataSource, DataSourceProperties properties) { DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setDataLocations(scriptLocations(properties.getData(), "data", properties.getPlatform())); @@ -125,7 +125,7 @@ class DataSourceInitializationConfiguration { settings.setMode(mapMode(properties.getInitializationMode())); DataSource initializationDataSource = determineDataSource(dataSource::getObject, properties.getDataUsername(), properties.getDataPassword()); - return new DataSourceScriptDatabaseInitializer(initializationDataSource, settings); + return new SqlDataSourceScriptDatabaseInitializer(initializationDataSource, settings); } static class DifferentCredentialsCondition extends AnyNestedCondition { @@ -157,7 +157,7 @@ class DataSourceInitializationConfiguration { static class SharedCredentialsDataSourceInitializationConfiguration { @Bean - DataSourceScriptDatabaseInitializer scriptDataSourceInitializer(DataSource dataSource, + SqlDataSourceScriptDatabaseInitializer scriptDataSourceInitializer(DataSource dataSource, DataSourceProperties properties) { DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); settings.setSchemaLocations(scriptLocations(properties.getSchema(), "schema", properties.getPlatform())); @@ -166,7 +166,7 @@ class DataSourceInitializationConfiguration { settings.setSeparator(properties.getSeparator()); settings.setEncoding(properties.getSqlScriptEncoding()); settings.setMode(mapMode(properties.getInitializationMode())); - return new DataSourceScriptDatabaseInitializer(dataSource, settings); + return new SqlDataSourceScriptDatabaseInitializer(dataSource, settings); } static class DataSourceInitializationCondition extends SpringBootCondition { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java index 84eeca6ad9..f6f53a29af 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java @@ -30,7 +30,6 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; import org.springframework.util.Assert; @@ -101,7 +100,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB * using the available DDL and DML scripts. */ @Deprecated - private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED; + private org.springframework.boot.jdbc.DataSourceInitializationMode initializationMode = org.springframework.boot.jdbc.DataSourceInitializationMode.EMBEDDED; /** * Platform to use in the DDL or DML scripts (such as schema-${platform}.sql or @@ -394,12 +393,12 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB @Deprecated @DeprecatedConfigurationProperty(replacement = "spring.sql.init.mode") - public DataSourceInitializationMode getInitializationMode() { + public org.springframework.boot.jdbc.DataSourceInitializationMode getInitializationMode() { return this.initializationMode; } @Deprecated - public void setInitializationMode(DataSourceInitializationMode initializationMode) { + public void setInitializationMode(org.springframework.boot.jdbc.DataSourceInitializationMode initializationMode) { this.initializationMode = initializationMode; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 96ab880471..1c7b5df2e3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -44,7 +44,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; -import org.springframework.core.io.ResourceLoader; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SpringBeanJobFactory; import org.springframework.transaction.PlatformTransactionManager; @@ -132,12 +131,14 @@ public class QuartzAutoConfiguration { } @Bean - @ConditionalOnMissingBean - public QuartzDataSourceInitializer quartzDataSourceInitializer(DataSource dataSource, - @QuartzDataSource ObjectProvider quartzDataSource, ResourceLoader resourceLoader, + @SuppressWarnings("deprecation") + @ConditionalOnMissingBean({ QuartzDataSourceScriptDatabaseInitializer.class, + QuartzDataSourceInitializer.class }) + public QuartzDataSourceScriptDatabaseInitializer quartzDataSourceScriptDatabaseInitializer( + DataSource dataSource, @QuartzDataSource ObjectProvider quartzDataSource, QuartzProperties properties) { DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource); - return new QuartzDataSourceInitializer(dataSourceToUse, resourceLoader, properties); + return new QuartzDataSourceScriptDatabaseInitializer(dataSourceToUse, properties); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializer.java index aeab5908c4..55539c4d47 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializer.java @@ -18,8 +18,7 @@ package org.springframework.boot.autoconfigure.quartz; import javax.sql.DataSource; -import org.springframework.boot.jdbc.AbstractDataSourceInitializer; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.util.Assert; @@ -29,8 +28,11 @@ import org.springframework.util.Assert; * * @author Vedran Pavic * @since 2.0.0 + * @deprecated since 2.6.0 for removal in 2.8.0 in favor of + * {@link QuartzDataSourceScriptDatabaseInitializer} */ -public class QuartzDataSourceInitializer extends AbstractDataSourceInitializer { +@Deprecated +public class QuartzDataSourceInitializer extends org.springframework.boot.jdbc.AbstractDataSourceInitializer { private final QuartzProperties properties; @@ -47,8 +49,17 @@ public class QuartzDataSourceInitializer extends AbstractDataSourceInitializer { } @Override - protected DataSourceInitializationMode getMode() { - return this.properties.getJdbc().getInitializeSchema(); + protected org.springframework.boot.jdbc.DataSourceInitializationMode getMode() { + DatabaseInitializationMode mode = this.properties.getJdbc().getInitializeSchema(); + switch (mode) { + case ALWAYS: + return org.springframework.boot.jdbc.DataSourceInitializationMode.ALWAYS; + case EMBEDDED: + return org.springframework.boot.jdbc.DataSourceInitializationMode.EMBEDDED; + case NEVER: + default: + return org.springframework.boot.jdbc.DataSourceInitializationMode.NEVER; + } } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java new file mode 100644 index 0000000000..71d3548b9a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.quartz; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; + +/** + * {@link DataSourceScriptDatabaseInitializer} for the Quartz Scheduler database. May be + * registered as a bean to override auto-configuration. + * + * @author Vedran Pavic + * @author Andy Wilkinson + * @author Phillip Webb + * @since 2.6.0 + */ +public class QuartzDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { + + /** + * Create a new {@link QuartzDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Quartz Scheduler data source + * @param properties the Quartz properties + * @see #getSettings + */ + public QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, QuartzProperties properties) { + this(dataSource, getSettings(dataSource, properties)); + } + + /** + * Create a new {@link QuartzDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Quartz Scheduler data source + * @param settings the database initialization settings + * @see #getSettings + */ + public QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { + super(dataSource, settings); + } + + /** + * Adapts {@link QuartzProperties Quartz properties} to + * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} + * placeholders. + * @param dataSource the Quartz Scheduler data source + * @param properties the Quartz properties + * @return a new {@link DatabaseInitializationSettings} instance + * @see #QuartzDataSourceScriptDatabaseInitializer(DataSource, + * DatabaseInitializationSettings) + */ + public static DatabaseInitializationSettings getSettings(DataSource dataSource, QuartzProperties properties) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.DB2, "db2_v95"); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MYSQL, "mysql_innodb"); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MYSQL, "mysql_innodb"); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.POSTGRESQL, "postgres"); + platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.SQLSERVER, "sqlServer"); + settings.setSchemaLocations(platformResolver.resolveAll(dataSource, properties.getJdbc().getSchema())); + settings.setMode(properties.getJdbc().getInitializeSchema()); + settings.setContinueOnError(true); + return settings; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index 3509ddbb3f..03da194afb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import java.util.List; import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; /** * Configuration properties for the Quartz Scheduler integration. @@ -144,7 +144,7 @@ public class QuartzProperties { /** * Database schema initialization mode. */ - private DataSourceInitializationMode initializeSchema = DataSourceInitializationMode.EMBEDDED; + private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; /** * Prefixes for single-line comments in SQL initialization scripts. @@ -159,11 +159,11 @@ public class QuartzProperties { this.schema = schema; } - public DataSourceInitializationMode getInitializeSchema() { + public DatabaseInitializationMode getInitializeSchema() { return this.initializeSchema; } - public void setInitializeSchema(DataSourceInitializationMode initializeSchema) { + public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { this.initializeSchema = initializeSchema; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/SchedulerFactoryBeanCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/SchedulerFactoryBeanCustomizer.java index 30584ca4b9..b6a057799c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/SchedulerFactoryBeanCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/SchedulerFactoryBeanCustomizer.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import org.springframework.scheduling.quartz.SchedulerFactoryBean; * For customization of the {@link DataSource} used by Quartz, use of * {@link QuartzDataSource @QuartzDataSource} is preferred. It will ensure consistent * customization of both the {@link SchedulerFactoryBean} and the - * {@link QuartzDataSourceInitializer}. + * {@link QuartzDataSourceScriptDatabaseInitializer}. * * @author Vedran Pavic * @since 2.0.0 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java index 11f50c9621..b4d151e3c1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -35,7 +36,7 @@ import org.springframework.context.annotation.Import; */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(ConnectionFactory.class) -@AutoConfigureBefore(DataSourceAutoConfiguration.class) +@AutoConfigureBefore({ DataSourceAutoConfiguration.class, SqlInitializationAutoConfiguration.class }) @EnableConfigurationProperties(R2dbcProperties.class) @Import({ ConnectionFactoryConfigurations.Pool.class, ConnectionFactoryConfigurations.Generic.class, ConnectionFactoryDependentConfiguration.class }) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java index 934b85e76c..65fa4d7dbe 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java @@ -32,7 +32,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.session.SessionRepository; import org.springframework.session.jdbc.JdbcIndexedSessionRepository; @@ -56,12 +55,14 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi class JdbcSessionConfiguration { @Bean - @ConditionalOnMissingBean - JdbcSessionDataSourceInitializer jdbcSessionDataSourceInitializer( + @SuppressWarnings("deprecation") + @ConditionalOnMissingBean({ JdbcSessionDataSourceScriptDatabaseInitializer.class, + JdbcSessionDataSourceInitializer.class }) + JdbcSessionDataSourceScriptDatabaseInitializer jdbcSessionDataSourceScriptDatabaseInitializer( @SpringSessionDataSource ObjectProvider sessionDataSource, - ObjectProvider dataSource, ResourceLoader resourceLoader, JdbcSessionProperties properties) { - return new JdbcSessionDataSourceInitializer(sessionDataSource.getIfAvailable(dataSource::getObject), - resourceLoader, properties); + ObjectProvider dataSource, JdbcSessionProperties properties) { + DataSource dataSourceToInitialize = sessionDataSource.getIfAvailable(dataSource::getObject); + return new JdbcSessionDataSourceScriptDatabaseInitializer(dataSourceToInitialize, properties); } @Configuration(proxyBeanMethods = false) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceInitializer.java index 4dd4c9f2d8..15078aaa56 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceInitializer.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -18,8 +18,7 @@ package org.springframework.boot.autoconfigure.session; import javax.sql.DataSource; -import org.springframework.boot.jdbc.AbstractDataSourceInitializer; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; @@ -28,8 +27,11 @@ import org.springframework.util.Assert; * * @author Vedran Pavic * @since 1.4.0 + * @deprecated since 2.6.0 for removal in 2.8.0 in favor of + * {@link JdbcSessionDataSourceScriptDatabaseInitializer} */ -public class JdbcSessionDataSourceInitializer extends AbstractDataSourceInitializer { +@Deprecated +public class JdbcSessionDataSourceInitializer extends org.springframework.boot.jdbc.AbstractDataSourceInitializer { private final JdbcSessionProperties properties; @@ -41,8 +43,17 @@ public class JdbcSessionDataSourceInitializer extends AbstractDataSourceInitiali } @Override - protected DataSourceInitializationMode getMode() { - return this.properties.getInitializeSchema(); + protected org.springframework.boot.jdbc.DataSourceInitializationMode getMode() { + DatabaseInitializationMode mode = this.properties.getInitializeSchema(); + switch (mode) { + case ALWAYS: + return org.springframework.boot.jdbc.DataSourceInitializationMode.ALWAYS; + case EMBEDDED: + return org.springframework.boot.jdbc.DataSourceInitializationMode.EMBEDDED; + case NEVER: + default: + return org.springframework.boot.jdbc.DataSourceInitializationMode.NEVER; + } } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java new file mode 100644 index 0000000000..851694049b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.session; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; + +/** + * {@link DataSourceScriptDatabaseInitializer} for the Spring Session JDBC database. May + * be registered as a bean to override auto-configuration. + * + * @author Dave Syer + * @author Vedran Pavic + * @author Andy Wilkinson + * @author Phillip Webb + * @since 2.6.0 + */ +public class JdbcSessionDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { + + /** + * Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Spring Session JDBC data source + * @param properties the Spring Session JDBC properties + * @see #getSettings + */ + public JdbcSessionDataSourceScriptDatabaseInitializer(DataSource dataSource, JdbcSessionProperties properties) { + this(dataSource, getSettings(dataSource, properties)); + } + + /** + * Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the Spring Session JDBC data source + * @param settings the database initialization settings + * @see #getSettings + */ + public JdbcSessionDataSourceScriptDatabaseInitializer(DataSource dataSource, + DatabaseInitializationSettings settings) { + super(dataSource, settings); + } + + /** + * Adapts {@link JdbcSessionProperties Spring Session JDBC properties} to + * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} + * placeholders. + * @param dataSource the Spring Session JDBC data source + * @param properties the Spring Session JDBC properties + * @return a new {@link DatabaseInitializationSettings} instance + * @see #JdbcSessionDataSourceScriptDatabaseInitializer(DataSource, + * DatabaseInitializationSettings) + */ + static DatabaseInitializationSettings getSettings(DataSource dataSource, JdbcSessionProperties properties) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); + settings.setSchemaLocations(platformResolver.resolveAll(dataSource, properties.getSchema())); + settings.setMode(properties.getInitializeSchema()); + settings.setContinueOnError(true); + return settings; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java index 4a0dee835a..3cde29abcd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.session; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.session.FlushMode; import org.springframework.session.SaveMode; @@ -55,7 +55,7 @@ public class JdbcSessionProperties { /** * Database schema initialization mode. */ - private DataSourceInitializationMode initializeSchema = DataSourceInitializationMode.EMBEDDED; + private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; /** * Sessions flush mode. Determines when session changes are written to the session @@ -93,11 +93,11 @@ public class JdbcSessionProperties { this.cleanupCron = cleanupCron; } - public DataSourceInitializationMode getInitializeSchema() { + public DatabaseInitializationMode getInitializeSchema() { return this.initializeSchema; } - public void setInitializeSchema(DataSourceInitializationMode initializeSchema) { + public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { this.initializeSchema = initializeSchema; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.java index b591991cb5..69bf55f10c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.java @@ -22,9 +22,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; -import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; -import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.SimpleDriverDataSource; @@ -32,17 +29,16 @@ import org.springframework.jdbc.datasource.init.DatabasePopulator; import org.springframework.util.StringUtils; @Configuration(proxyBeanMethods = false) -@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class) +@ConditionalOnMissingBean({ SqlDataSourceScriptDatabaseInitializer.class, SqlR2dbcScriptDatabaseInitializer.class }) @ConditionalOnSingleCandidate(DataSource.class) @ConditionalOnClass(DatabasePopulator.class) class DataSourceInitializationConfiguration { @Bean - DataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, - SqlInitializationProperties initializationProperties) { - DatabaseInitializationSettings settings = SettingsCreator.createFrom(initializationProperties); - return new DataSourceScriptDatabaseInitializer(determineDataSource(dataSource, - initializationProperties.getUsername(), initializationProperties.getPassword()), settings); + SqlDataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, + SqlInitializationProperties properties) { + return new SqlDataSourceScriptDatabaseInitializer( + determineDataSource(dataSource, properties.getUsername(), properties.getPassword()), properties); } private static DataSource determineDataSource(DataSource dataSource, String username, String password) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/R2dbcInitializationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/R2dbcInitializationConfiguration.java index cff498adaf..8b4bbbf0e7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/R2dbcInitializationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/R2dbcInitializationConfiguration.java @@ -19,10 +19,9 @@ package org.springframework.boot.autoconfigure.sql.init; import io.r2dbc.spi.ConnectionFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.r2dbc.ConnectionFactoryBuilder; -import org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer; -import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.r2dbc.connection.init.DatabasePopulator; @@ -37,15 +36,15 @@ import org.springframework.util.StringUtils; @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ ConnectionFactory.class, DatabasePopulator.class }) @ConditionalOnSingleCandidate(ConnectionFactory.class) +@ConditionalOnMissingBean({ SqlR2dbcScriptDatabaseInitializer.class, SqlDataSourceScriptDatabaseInitializer.class }) class R2dbcInitializationConfiguration { @Bean - R2dbcScriptDatabaseInitializer r2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory, + SqlR2dbcScriptDatabaseInitializer r2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory, SqlInitializationProperties properties) { - DatabaseInitializationSettings settings = SettingsCreator.createFrom(properties); - return new R2dbcScriptDatabaseInitializer( + return new SqlR2dbcScriptDatabaseInitializer( determineConnectionFactory(connectionFactory, properties.getUsername(), properties.getPassword()), - settings); + properties); } private static ConnectionFactory determineConnectionFactory(ConnectionFactory connectionFactory, String username, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SettingsCreator.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SettingsCreator.java index c4e276de4d..a60c93c041 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SettingsCreator.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SettingsCreator.java @@ -30,7 +30,6 @@ import org.springframework.boot.sql.init.DatabaseInitializationSettings; final class SettingsCreator { private SettingsCreator() { - } static DatabaseInitializationSettings createFrom(SqlInitializationProperties properties) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlDataSourceScriptDatabaseInitializer.java new file mode 100644 index 0000000000..a4b0e69f7c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.sql.init; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; + +/** + * {@link DataSourceScriptDatabaseInitializer} for the primary SQL database. May be + * registered as a bean to override auto-configuration. + * + * @author Andy Wilkinson + * @author Phillip Webb + * @since 2.6.0 + */ +public class SqlDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { + + /** + * Create a new {@link SqlDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the primary SQL data source + * @param properties the SQL initialization properties + * @see #getSettings + */ + public SqlDataSourceScriptDatabaseInitializer(DataSource dataSource, SqlInitializationProperties properties) { + this(dataSource, getSettings(properties)); + } + + /** + * Create a new {@link SqlDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the primary SQL data source + * @param settings the database initialization settings + * @see #getSettings + */ + public SqlDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { + super(dataSource, settings); + } + + /** + * Adapts {@link SqlInitializationProperties SQL initialization properties} to + * {@link DatabaseInitializationSettings}. + * @param properties the SQL initialization properties + * @return a new {@link DatabaseInitializationSettings} instance + * @see #SqlDataSourceScriptDatabaseInitializer(DataSource, + * DatabaseInitializationSettings) + */ + public static DatabaseInitializationSettings getSettings(SqlInitializationProperties properties) { + return SettingsCreator.createFrom(properties); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java index 6ec161671a..9591376e3a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfiguration.java @@ -18,14 +18,12 @@ package org.springframework.boot.autoconfigure.sql.init; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.NoneNestedConditions; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration.SqlInitializationModeCondition; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -38,7 +36,6 @@ import org.springframework.context.annotation.Import; * @since 2.5.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class) @AutoConfigureAfter({ R2dbcAutoConfiguration.class, DataSourceAutoConfiguration.class }) @EnableConfigurationProperties(SqlInitializationProperties.class) @Import({ DatabaseInitializationDependencyConfigurer.class, R2dbcInitializationConfiguration.class, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlR2dbcScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlR2dbcScriptDatabaseInitializer.java new file mode 100644 index 0000000000..a3730c466e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/sql/init/SqlR2dbcScriptDatabaseInitializer.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.sql.init; + +import io.r2dbc.spi.ConnectionFactory; + +import org.springframework.boot.autoconfigure.batch.BatchDataSourceScriptDatabaseInitializer; +import org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; + +/** + * {@link R2dbcScriptDatabaseInitializer} for the primary SQL database. May be registered + * as a bean to override auto-configuration. + * + * @author Andy Wilkinson + * @author Phillip Webb + * @since 2.6.0 + */ +public class SqlR2dbcScriptDatabaseInitializer extends R2dbcScriptDatabaseInitializer { + + /** + * Create a new {@link SqlDataSourceScriptDatabaseInitializer} instance. + * @param connectionFactory the primary SQL connection factory + * @param properties the SQL initialization properties + * @see #getSettings + */ + public SqlR2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory, + SqlInitializationProperties properties) { + super(connectionFactory, getSettings(properties)); + } + + /** + * Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance. + * @param connectionFactory the primary SQL connection factory + * @param settings the database initialization settings + * @see #getSettings + */ + public SqlR2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory, + DatabaseInitializationSettings settings) { + super(connectionFactory, settings); + } + + /** + * Adapts {@link SqlInitializationProperties SQL initialization properties} to + * {@link DatabaseInitializationSettings}. + * @param properties the SQL initialization properties + * @return a new {@link DatabaseInitializationSettings} instance + * @see #SqlR2dbcScriptDatabaseInitializer(ConnectionFactory, + * DatabaseInitializationSettings) + */ + public static DatabaseInitializationSettings getSettings(SqlInitializationProperties properties) { + return SettingsCreator.createFrom(properties); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java index 639a95b0b7..ae6b398eb8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java @@ -45,19 +45,24 @@ import org.springframework.boot.DefaultApplicationArguments; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; @@ -88,7 +93,7 @@ class BatchAutoConfigurationTests { assertThat(context).hasSingleBean(JobLauncher.class); assertThat(context).hasSingleBean(JobExplorer.class); assertThat(context.getBean(BatchProperties.class).getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.EMBEDDED); + .isEqualTo(DatabaseInitializationMode.EMBEDDED); assertThat(new JdbcTemplate(context.getBean(DataSource.class)) .queryForList("select * from BATCH_JOB_EXECUTION")).isEmpty(); }); @@ -198,7 +203,7 @@ class BatchAutoConfigurationTests { return (context) -> { assertThat(context).hasSingleBean(JobLauncher.class); assertThat(context.getBean(BatchProperties.class).getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.NEVER); + .isEqualTo(DatabaseInitializationMode.NEVER); assertThatExceptionOfType(BadSqlGrammarException.class) .isThrownBy(() -> new JdbcTemplate(context.getBean(DataSource.class)) .queryForList("select * from BATCH_JOB_EXECUTION")); @@ -248,7 +253,7 @@ class BatchAutoConfigurationTests { return (context) -> { assertThat(context).hasSingleBean(JobLauncher.class); assertThat(context.getBean(BatchProperties.class).getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.EMBEDDED); + .isEqualTo(DatabaseInitializationMode.EMBEDDED); assertThat(new JdbcTemplate(context.getBean(DataSource.class)) .queryForList("select * from PREFIX_JOB_EXECUTION")).isEmpty(); JobExplorer jobExplorer = context.getBean(JobExplorer.class); @@ -293,11 +298,11 @@ class BatchAutoConfigurationTests { this.contextRunner.withUserConfiguration(TestConfiguration.class, BatchDataSourceConfiguration.class) .run((context) -> { assertThat(context).hasSingleBean(BatchConfigurer.class) - .hasSingleBean(BatchDataSourceInitializer.class).hasBean("batchDataSource"); + .hasSingleBean(BatchDataSourceScriptDatabaseInitializer.class).hasBean("batchDataSource"); DataSource batchDataSource = context.getBean("batchDataSource", DataSource.class); assertThat(context.getBean(BatchConfigurer.class)).hasFieldOrPropertyWithValue("dataSource", batchDataSource); - assertThat(context.getBean(BatchDataSourceInitializer.class)) + assertThat(context.getBean(BatchDataSourceScriptDatabaseInitializer.class)) .hasFieldOrPropertyWithValue("dataSource", batchDataSource); }); } @@ -346,6 +351,37 @@ class BatchAutoConfigurationTests { }); } + @Test + void whenTheUserDefinesTheirOwnBatchDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner + .withUserConfiguration(TestConfiguration.class, CustomBatchDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .run((context) -> assertThat(context).hasSingleBean(BatchDataSourceScriptDatabaseInitializer.class) + .doesNotHaveBean("batchDataSourceScriptDatabaseInitializer").hasBean("customInitializer")); + } + + @Test + @Deprecated + @SuppressWarnings("deprecation") + void whenTheUserDefinesTheirOwnBatchDataSourceInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner + .withUserConfiguration(TestConfiguration.class, CustomBatchDataSourceInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .run((context) -> assertThat(context).doesNotHaveBean(BatchDataSourceScriptDatabaseInitializer.class) + .hasSingleBean(BatchDataSourceInitializer.class).hasBean("customInitializer")); + } + + @Test + void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredBatchInitializerRemains() { + this.contextRunner.withUserConfiguration(TestConfiguration.class, CustomDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .run((context) -> assertThat(context).hasSingleBean(BatchDataSourceScriptDatabaseInitializer.class) + .hasBean("customInitializer")); + } + @Configuration(proxyBeanMethods = false) protected static class BatchDataSourceConfiguration { @@ -490,4 +526,36 @@ class BatchAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class CustomBatchDatabaseInitializerConfiguration { + + @Bean + BatchDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource, BatchProperties properties) { + return new BatchDataSourceScriptDatabaseInitializer(dataSource, properties.getJdbc()); + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomDatabaseInitializerConfiguration { + + @Bean + DataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) { + return new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings()); + } + + } + + @Deprecated + @Configuration(proxyBeanMethods = false) + static class CustomBatchDataSourceInitializerConfiguration { + + @Bean + BatchDataSourceInitializer customInitializer(DataSource dataSource, ResourceLoader resourceLoader, + BatchProperties properties) { + return new BatchDataSourceInitializer(dataSource, resourceLoader, properties); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationWithoutJpaTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationWithoutJpaTests.java index a7bc4c83d4..2a7562919e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationWithoutJpaTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationWithoutJpaTests.java @@ -30,7 +30,7 @@ import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; @@ -62,7 +62,7 @@ class BatchAutoConfigurationWithoutJpaTests { assertThat(context.getBean(PlatformTransactionManager.class).toString()) .contains("DataSourceTransactionManager"); assertThat(context.getBean(BatchProperties.class).getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.EMBEDDED); + .isEqualTo(DatabaseInitializationMode.EMBEDDED); assertThat(new JdbcTemplate(context.getBean(DataSource.class)) .queryForList("select * from BATCH_JOB_EXECUTION")).isEmpty(); assertThat(context.getBean(JobExplorer.class).findRunningJobExecutions("test")).isEmpty(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunnerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunnerTests.java index b80bedb45d..b9d0e26ab6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunnerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunnerTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.batch; +import java.util.Arrays; import java.util.List; import javax.sql.DataSource; @@ -44,11 +45,12 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ResourceLoader; import org.springframework.transaction.PlatformTransactionManager; import static org.assertj.core.api.Assertions.assertThat; @@ -226,8 +228,10 @@ class JobLauncherApplicationRunnerTests { } @Bean - BatchDataSourceInitializer batchDataSourceInitializer(ResourceLoader resourceLoader) { - return new BatchDataSourceInitializer(this.dataSource, resourceLoader, new BatchProperties()); + DataSourceScriptDatabaseInitializer batchDataSourceInitializer() { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + settings.setSchemaLocations(Arrays.asList("classpath:org/springframework/batch/core/schema-h2.sql")); + return new DataSourceScriptDatabaseInitializer(this.dataSource, settings); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index 03d1f5cc86..0069e49993 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.integration; import javax.management.MBeanServer; +import javax.sql.DataSource; import io.rsocket.transport.ClientTransport; import io.rsocket.transport.netty.client.TcpClientTransport; @@ -26,6 +27,7 @@ import reactor.core.publisher.Mono; import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration.IntegrationComponentScanConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; @@ -35,11 +37,14 @@ import org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfig import org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration; import org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration; import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ResourceLoader; import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.config.IntegrationManagementConfigurer; @@ -155,8 +160,7 @@ class IntegrationAutoConfigurationTests { "spring.integration.jdbc.initialize-schema=always") .run((context) -> { IntegrationProperties properties = context.getBean(IntegrationProperties.class); - assertThat(properties.getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.ALWAYS); + assertThat(properties.getJdbc().getInitializeSchema()).isEqualTo(DatabaseInitializationMode.ALWAYS); JdbcOperations jdbc = context.getBean(JdbcOperations.class); assertThat(jdbc.queryForList("select * from INT_MESSAGE")).isEmpty(); assertThat(jdbc.queryForList("select * from INT_GROUP_TO_MESSAGE")).isEmpty(); @@ -175,8 +179,7 @@ class IntegrationAutoConfigurationTests { "spring.integration.jdbc.initialize-schema=never") .run((context) -> { IntegrationProperties properties = context.getBean(IntegrationProperties.class); - assertThat(properties.getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.NEVER); + assertThat(properties.getJdbc().getInitializeSchema()).isEqualTo(DatabaseInitializationMode.NEVER); JdbcOperations jdbc = context.getBean(JdbcOperations.class); assertThatExceptionOfType(BadSqlGrammarException.class) .isThrownBy(() -> jdbc.queryForList("select * from INT_MESSAGE")); @@ -191,7 +194,7 @@ class IntegrationAutoConfigurationTests { .withPropertyValues("spring.datasource.generate-unique-name=true").run((context) -> { IntegrationProperties properties = context.getBean(IntegrationProperties.class); assertThat(properties.getJdbc().getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.EMBEDDED); + .isEqualTo(DatabaseInitializationMode.EMBEDDED); JdbcOperations jdbc = context.getBean(JdbcOperations.class); assertThat(jdbc.queryForList("select * from INT_MESSAGE")).isEmpty(); }); @@ -336,6 +339,39 @@ class IntegrationAutoConfigurationTests { }); } + @Test + void whenTheUserDefinesTheirOwnIntegrationDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner.withUserConfiguration(CustomIntegrationDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .run((context) -> assertThat(context) + .hasSingleBean(IntegrationDataSourceScriptDatabaseInitializer.class) + .doesNotHaveBean("integrationDataSourceScriptDatabaseInitializer") + .hasBean("customInitializer")); + } + + @Test + @Deprecated + @SuppressWarnings("deprecation") + void whenTheUserDefinesTheirOwnIntegrationDataSourceInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner.withUserConfiguration(CustomIntegrationDataSourceInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .run((context) -> assertThat(context) + .doesNotHaveBean(IntegrationDataSourceScriptDatabaseInitializer.class) + .hasSingleBean(IntegrationDataSourceInitializer.class).hasBean("customInitializer")); + } + + @Test + void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredIntegrationInitializerRemains() { + this.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .run((context) -> assertThat(context) + .hasSingleBean(IntegrationDataSourceScriptDatabaseInitializer.class) + .hasBean("customInitializer")); + } + @Configuration(proxyBeanMethods = false) static class CustomMBeanExporter { @@ -390,4 +426,37 @@ class IntegrationAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class CustomIntegrationDatabaseInitializerConfiguration { + + @Bean + IntegrationDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource, + IntegrationProperties properties) { + return new IntegrationDataSourceScriptDatabaseInitializer(dataSource, properties.getJdbc()); + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomDatabaseInitializerConfiguration { + + @Bean + DataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) { + return new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings()); + } + + } + + @Deprecated + @Configuration(proxyBeanMethods = false) + static class CustomIntegrationDataSourceInitializerConfiguration { + + @Bean + IntegrationDataSourceInitializer customInitializer(DataSource dataSource, ResourceLoader resourceLoader, + IntegrationProperties properties) { + return new IntegrationDataSourceInitializer(dataSource, resourceLoader, properties); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index f8d6f6769f..c64adebd80 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -50,6 +50,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; @@ -61,6 +63,7 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.scheduling.quartz.LocalDataSourceJobStore; @@ -78,6 +81,7 @@ import static org.mockito.Mockito.verifyNoInteractions; * * @author Vedran Pavic * @author Stephane Nicoll + * @author Andy Wilkinson */ @ExtendWith(OutputCaptureExtension.class) class QuartzAutoConfigurationTests { @@ -151,16 +155,20 @@ class QuartzAutoConfigurationTests { }); } - private ContextConsumer assertDataSourceJobStore(String datasourceName) { + private ContextConsumer assertDataSourceJobStore(String dataSourceName) { return (context) -> { assertThat(context).hasSingleBean(Scheduler.class); Scheduler scheduler = context.getBean(Scheduler.class); assertThat(scheduler.getMetaData().getJobStoreClass()).isAssignableFrom(LocalDataSourceJobStore.class); - JdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(datasourceName, DataSource.class)); + JdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(dataSourceName, DataSource.class)); assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM QRTZ_JOB_DETAILS", Integer.class)) .isEqualTo(2); assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM QRTZ_SIMPLE_TRIGGERS", Integer.class)) .isEqualTo(0); + assertThat(context).hasSingleBean(QuartzDataSourceScriptDatabaseInitializer.class); + QuartzDataSourceScriptDatabaseInitializer initializer = context + .getBean(QuartzDataSourceScriptDatabaseInitializer.class); + assertThat(initializer).hasFieldOrPropertyWithValue("dataSource", context.getBean(dataSourceName)); }; } @@ -313,6 +321,37 @@ class QuartzAutoConfigurationTests { this.contextRunner.withPropertyValues().run(assertSchedulerName("quartzScheduler")); } + @Test + void whenTheUserDefinesTheirOwnQuartzDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner.withUserConfiguration(CustomQuartzDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.quartz.job-store-type=jdbc") + .run((context) -> assertThat(context).hasSingleBean(QuartzDataSourceScriptDatabaseInitializer.class) + .doesNotHaveBean("quartzDataSourceScriptDatabaseInitializer").hasBean("customInitializer")); + } + + @Test + @Deprecated + @SuppressWarnings("deprecation") + void whenTheUserDefinesTheirOwnQuartzDataSourceInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner.withUserConfiguration(CustomQuartzDataSourceInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.quartz.job-store-type=jdbc") + .run((context) -> assertThat(context).doesNotHaveBean(QuartzDataSourceScriptDatabaseInitializer.class) + .hasSingleBean(QuartzDataSourceInitializer.class).hasBean("customInitializer")); + } + + @Test + void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredQuartzInitializerRemains() { + this.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.quartz.job-store-type=jdbc").run((context) -> assertThat(context) + .hasSingleBean(QuartzDataSourceScriptDatabaseInitializer.class).hasBean("customInitializer")); + } + private ContextConsumer assertSchedulerName(String schedulerName) { return (context) -> { assertThat(context).hasSingleBean(SchedulerFactoryBean.class); @@ -491,6 +530,39 @@ class QuartzAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class CustomQuartzDatabaseInitializerConfiguration { + + @Bean + QuartzDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource, + QuartzProperties properties) { + return new QuartzDataSourceScriptDatabaseInitializer(dataSource, properties); + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomDatabaseInitializerConfiguration { + + @Bean + DataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) { + return new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings()); + } + + } + + @Deprecated + @Configuration(proxyBeanMethods = false) + static class CustomQuartzDataSourceInitializerConfiguration { + + @Bean + QuartzDataSourceInitializer customInitializer(DataSource dataSource, ResourceLoader resourceLoader, + QuartzProperties properties) { + return new QuartzDataSourceInitializer(dataSource, resourceLoader, properties); + } + + } + static class ComponentThatUsesScheduler { ComponentThatUsesScheduler(Scheduler scheduler) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializerTests.java index 6a4d980e02..89cc607474 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceInitializerTests.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Stephane Nicoll */ +@Deprecated class QuartzDataSourceInitializerTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java index 487a224ea6..63667a1c70 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java @@ -30,7 +30,9 @@ import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.session.JdbcSessionConfiguration.SpringBootJdbcHttpSessionConfiguration; import org.springframework.boot.autoconfigure.web.ServerProperties; -import org.springframework.boot.jdbc.DataSourceInitializationMode; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; +import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; @@ -38,6 +40,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.session.FlushMode; @@ -85,7 +88,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration (int) new ServerProperties().getServlet().getSession().getTimeout().getSeconds()); assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION"); assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.EMBEDDED); + .isEqualTo(DatabaseInitializationMode.EMBEDDED); assertThat(context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")).isEmpty(); SpringBootJdbcHttpSessionConfiguration configuration = context .getBean(SpringBootJdbcHttpSessionConfiguration.class); @@ -111,7 +114,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration JdbcIndexedSessionRepository.class); assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION"); assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.NEVER); + .isEqualTo(DatabaseInitializationMode.NEVER); assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy( () -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")); }); @@ -137,7 +140,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration JdbcIndexedSessionRepository.class); assertThat(repository).hasFieldOrPropertyWithValue("tableName", "FOO_BAR"); assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema()) - .isEqualTo(DataSourceInitializationMode.EMBEDDED); + .isEqualTo(DatabaseInitializationMode.EMBEDDED); assertThat(context.getBean(JdbcOperations.class).queryForList("select * from FOO_BAR")).isEmpty(); }); } @@ -186,8 +189,11 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration .withPropertyValues("spring.session.store-type=jdbc").run((context) -> { JdbcIndexedSessionRepository repository = validateSessionRepository(context, JdbcIndexedSessionRepository.class); + DataSource sessionDataSource = context.getBean("sessionDataSource", DataSource.class); assertThat(repository).extracting("jdbcOperations").extracting("dataSource") - .isEqualTo(context.getBean("sessionDataSource")); + .isEqualTo(sessionDataSource); + assertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)) + .hasFieldOrPropertyWithValue("dataSource", sessionDataSource); assertThatExceptionOfType(BadSqlGrammarException.class).isThrownBy( () -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")); }); @@ -201,7 +207,7 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration assertThat(sessionRepositoryNames).isNotEmpty(); for (String sessionRepositoryName : sessionRepositoryNames) { assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn()) - .contains("jdbcSessionDataSourceInitializer"); + .contains("jdbcSessionDataSourceScriptDatabaseInitializer"); } }); } @@ -238,6 +244,42 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration }); } + @Test + void whenTheUserDefinesTheirOwnJdbcSessionDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner.withUserConfiguration(CustomJdbcSessionDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.session.store-type=jdbc") + .run((context) -> assertThat(context) + .hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class) + .doesNotHaveBean("jdbcSessionDataSourceScriptDatabaseInitializer") + .hasBean("customInitializer")); + } + + @Test + @Deprecated + @SuppressWarnings("deprecation") + void whenTheUserDefinesTheirOwnJdbcSessionDataSourceInitializerThenTheAutoConfiguredInitializerBacksOff() { + this.contextRunner.withUserConfiguration(CustomJdbcSessionDataSourceInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.session.store-type=jdbc") + .run((context) -> assertThat(context) + .doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class) + .hasSingleBean(JdbcSessionDataSourceInitializer.class).hasBean("customInitializer")); + } + + @Test + void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredJdbcSessionInitializerRemains() { + this.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.session.store-type=jdbc") + .run((context) -> assertThat(context) + .hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class) + .hasBean("customInitializer")); + } + @Configuration static class SessionDataSourceConfiguration { @@ -263,4 +305,37 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration } + @Configuration(proxyBeanMethods = false) + static class CustomJdbcSessionDatabaseInitializerConfiguration { + + @Bean + JdbcSessionDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource, + JdbcSessionProperties properties) { + return new JdbcSessionDataSourceScriptDatabaseInitializer(dataSource, properties); + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomDatabaseInitializerConfiguration { + + @Bean + DataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) { + return new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings()); + } + + } + + @Deprecated + @Configuration(proxyBeanMethods = false) + static class CustomJdbcSessionDataSourceInitializerConfiguration { + + @Bean + JdbcSessionDataSourceInitializer customInitializer(DataSource dataSource, ResourceLoader resourceLoader, + JdbcSessionProperties properties) { + return new JdbcSessionDataSourceInitializer(dataSource, resourceLoader, properties); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfigurationTests.java index 75552557b7..bc4f45d65b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/sql/init/SqlInitializationAutoConfigurationTests.java @@ -114,13 +114,20 @@ public class SqlInitializationAutoConfigurationTests { } @Test - void whenAnInitializerIsDefinedThenInitializerIsNotAutoConfigured() { + void whenAnSqlInitializerIsDefinedThenInitializerIsNotAutoConfigured() { this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class)) - .withUserConfiguration(DataSourceAutoConfiguration.class, DatabaseInitializerConfiguration.class) + .withUserConfiguration(DataSourceAutoConfiguration.class, SqlDatabaseInitializerConfiguration.class) .run((context) -> assertThat(context).hasSingleBean(AbstractScriptDatabaseInitializer.class) .hasBean("customInitializer")); } + @Test + void whenAnInitializerIsDefinedThenSqlInitializerIsStillAutoConfigured() { + this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) + .withUserConfiguration(DatabaseInitializerConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(SqlDataSourceScriptDatabaseInitializer.class).hasBean("customInitializer")); + } + @Test void whenBeanIsAnnotatedAsDependingOnDatabaseInitializationThenItDependsOnR2dbcScriptDatabaseInitializer() { this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class)) @@ -163,12 +170,45 @@ public class SqlInitializationAutoConfigurationTests { }); } + @Test + void whenDataSourceAutoConfigurationHasDefinedAnInitializerThenAutoConfigurationBacksOff() { + this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) + .withPropertyValues("spring.datasource.schema=classpath:schema.sql") + .withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO)).run((context) -> { + assertThat(context).hasSingleBean(SqlDataSourceScriptDatabaseInitializer.class); + assertThat(context).hasBean("scriptDataSourceInitializer"); + }); + } + + @Configuration(proxyBeanMethods = false) + static class SqlDatabaseInitializerConfiguration { + + @Bean + SqlDataSourceScriptDatabaseInitializer customInitializer() { + return new SqlDataSourceScriptDatabaseInitializer(null, new DatabaseInitializationSettings()) { + + @Override + protected void runScripts(List resources, boolean continueOnError, String separator, + Charset encoding) { + // No-op + } + + @Override + protected boolean isEmbeddedDatabase() { + return true; + } + + }; + } + + } + @Configuration(proxyBeanMethods = false) static class DatabaseInitializerConfiguration { @Bean - AbstractScriptDatabaseInitializer customInitializer() { - return new AbstractScriptDatabaseInitializer(new DatabaseInitializationSettings()) { + DataSourceScriptDatabaseInitializer customInitializer() { + return new DataSourceScriptDatabaseInitializer(null, new DatabaseInitializationSettings()) { @Override protected void runScripts(List resources, boolean continueOnError, String separator, diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializer.java index 9c7b39427f..fa23d5c703 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.sql.DatabaseMetaData; import javax.sql.DataSource; import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; @@ -34,7 +35,10 @@ import org.springframework.util.Assert; * @author Vedran Pavic * @author Stephane Nicoll * @since 1.5.0 + * @deprecated since 2.6.0 for removal in 2.8.0 in favor of + * {@link DataSourceScriptDatabaseInitializer} */ +@Deprecated public abstract class AbstractDataSourceInitializer implements InitializingBean { private static final String PLATFORM_PLACEHOLDER = "@@platform@@"; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java index e9ea33c233..355eead101 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java @@ -27,6 +27,7 @@ import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector; * * @author Henning Pƶttker */ +@Deprecated class AbstractDataSourceInitializerDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector { @Override diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceInitializationMode.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceInitializationMode.java index 9ac629d574..4e8bc01ed5 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceInitializationMode.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DataSourceInitializationMode.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.boot.jdbc; +import org.springframework.boot.sql.init.DatabaseInitializationMode; + /** * Supported {@link javax.sql.DataSource} initialization modes. * @@ -23,6 +25,8 @@ package org.springframework.boot.jdbc; * @author Stephane Nicoll * @since 2.0.0 * @see AbstractDataSourceInitializer + * @deprecated since 2.6.0 for removal in 2.8.0 in favor of + * {@link DatabaseInitializationMode} */ public enum DataSourceInitializationMode { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java index 3bb8b352cd..d381e5591a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java @@ -16,11 +16,15 @@ package org.springframework.boot.jdbc; +import java.sql.DatabaseMetaData; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Locale; +import javax.sql.DataSource; + +import org.springframework.jdbc.support.JdbcUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -316,4 +320,21 @@ public enum DatabaseDriver { return UNKNOWN; } + /** + * Find a {@link DatabaseDriver} for the given {@code DataSource}. + * @param dataSource data source to inspect + * @return the database driver of {@link #UNKNOWN} if not found + * @since 2.6.0 + */ + public static DatabaseDriver fromDataSource(DataSource dataSource) { + try { + String productName = JdbcUtils.commonDatabaseName( + JdbcUtils.extractDatabaseMetaData(dataSource, DatabaseMetaData::getDatabaseProductName)); + return DatabaseDriver.fromProductName(productName); + } + catch (Exception ex) { + return DatabaseDriver.UNKNOWN; + } + } + } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java index ccb131bc68..043bae2575 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java @@ -49,7 +49,7 @@ public class DataSourceScriptDatabaseInitializer extends AbstractScriptDatabaseI * Creates a new {@link DataSourceScriptDatabaseInitializer} that will initialize the * given {@code DataSource} using the given settings. * @param dataSource data source to initialize - * @param settings initialization settings + * @param settings the initialization settings */ public DataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { super(settings); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolver.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolver.java new file mode 100644 index 0000000000..748c55dee2 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolver.java @@ -0,0 +1,122 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.jdbc.init; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * Utility class that can resolve placholder text with the actual {@link DatabaseDriver} + * platform. + *

+ * By default, the name of the platform is the {@link DatabaseDriver#getId ID of the + * driver}. This mapping can be customized by + * {@link #withDriverPlatform(DatabaseDriver, String)} registering custom + * {@code DatabaseDriver} to platform mappings. + * + * @author Phillip Webb + * @author Andy Wilkinson + * @since 2.6.0 + */ +public class PlatformPlaceholderDatabaseDriverResolver { + + private final String placeholder; + + private final Map driverMappings; + + /** + * Creates a new resolver that will use the default {@code "@@platform@@"} + * placeholder. + */ + public PlatformPlaceholderDatabaseDriverResolver() { + this("@@platform@@"); + } + + /** + * Creates a new resolver that will use the given {@code placeholder}. + * @param placeholder the placeholder to use + */ + public PlatformPlaceholderDatabaseDriverResolver(String placeholder) { + this(placeholder, Collections.emptyMap()); + } + + private PlatformPlaceholderDatabaseDriverResolver(String placeholder, Map driverMappings) { + this.placeholder = placeholder; + this.driverMappings = driverMappings; + } + + /** + * Creates a new {@code PlatformPlaceholdDatabaseDriverResolver} that will map the + * given {@code driver} to the given {@code platform}. + * @param driver the driver + * @param platform the platform + * @return the new resolver + */ + public PlatformPlaceholderDatabaseDriverResolver withDriverPlatform(DatabaseDriver driver, String platform) { + Map driverMappings = new LinkedHashMap<>(this.driverMappings); + driverMappings.put(driver, platform); + return new PlatformPlaceholderDatabaseDriverResolver(this.placeholder, driverMappings); + } + + /** + * Resolves the placeholders in the given {@code values}, replacing them with the + * platform derived from the {@link DatabaseDriver} of the given {@code dataSource}. + * @param dataSource the DataSource from which the {@link DatabaseDriver} is derived + * @param values the values in which placeholders are resolved + * @return the values with their placeholders resolved + * @see DatabaseDriver#fromDataSource(DataSource) + */ + public List resolveAll(DataSource dataSource, String... values) { + Assert.notNull(dataSource, "DataSource must not be null"); + if (ObjectUtils.isEmpty(values)) { + return Collections.emptyList(); + } + List resolved = new ArrayList<>(values.length); + String platform = null; + for (String value : values) { + if (StringUtils.hasLength(value)) { + if (value.contains(this.placeholder)) { + platform = (platform != null) ? platform : determinePlatform(dataSource); + value = value.replace(this.placeholder, platform); + } + } + resolved.add(value); + } + return Collections.unmodifiableList(resolved); + } + + private String determinePlatform(DataSource dataSource) { + DatabaseDriver databaseDriver = getDatabaseDriver(dataSource); + Assert.state(databaseDriver != DatabaseDriver.UNKNOWN, "Unable to detect database type"); + return this.driverMappings.getOrDefault(databaseDriver, databaseDriver.getId()); + } + + DatabaseDriver getDatabaseDriver(DataSource dataSource) { + return DatabaseDriver.fromDataSource(dataSource); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDependencyConfigurationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDependencyConfigurationTests.java index 4a09876af3..e4a8ff23ff 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDependencyConfigurationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDependencyConfigurationTests.java @@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Andy Wilkinson */ +@Deprecated class AbstractDataSourceInitializerDependencyConfigurationTests { @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolverTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolverTests.java new file mode 100644 index 0000000000..6dbe746b3b --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolverTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.jdbc.init; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +import javax.sql.DataSource; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.jdbc.DatabaseDriver; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link PlatformPlaceholderDatabaseDriverResolver} + * + * @author Andy Wilkinson + */ +class PlatformPlaceholderDatabaseDriverResolverTests { + + @Test + void resolveAllWhenThereAreNoValuesShouldReturnEmptyList() { + assertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(mock(DataSource.class))).isEmpty(); + } + + @Test + void resolveAllWhenValueDoesNotContainPlaceholderShouldReturnValueUnchanged() { + assertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(mock(DataSource.class), "schema.sql")) + .containsExactly("schema.sql"); + } + + @Test + void resolveAllWhenValuesContainPlaceholdersShouldReturnValuesWithPlaceholdersReplaced() throws SQLException { + assertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(dataSourceWithProductName("PostgreSQL"), + "schema.sql", "schema-@@platform@@.sql", "data-@@platform@@.sql")).containsExactly("schema.sql", + "schema-postgresql.sql", "data-postgresql.sql"); + } + + @Test + void resolveAllWhenDriverMappingsAreCustomizedShouldResolvePlaceholderUsingCustomMapping() throws SQLException { + assertThat(new PlatformPlaceholderDatabaseDriverResolver() + .withDriverPlatform(DatabaseDriver.POSTGRESQL, "postgres") + .resolveAll(dataSourceWithProductName("PostgreSQL"), "schema-@@platform@@.sql")) + .containsExactly("schema-postgres.sql"); + } + + @Test + void resolveAllWhenValueIsAnEmptyStringShouldReturnValueUnchanged() { + assertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(mock(DataSource.class), "")) + .containsExactly(""); + } + + @Test + void resolveAllWhenDriverIsUnknownShouldThrow() { + assertThatIllegalStateException().isThrownBy(() -> new PlatformPlaceholderDatabaseDriverResolver() + .resolveAll(dataSourceWithProductName("CustomDB"), "schema-@@platform@@.sql")); + } + + @Test + void resolveAllWhenPlaceholderIsCustomizedShouldResolvePlaceholders() throws SQLException { + assertThat(new PlatformPlaceholderDatabaseDriverResolver("##platform##").resolveAll( + dataSourceWithProductName("PostgreSQL"), "schema-##platform##.sql", "schema-@@platform@@.sql")) + .containsExactly("schema-postgresql.sql", "schema-@@platform@@.sql"); + } + + private DataSource dataSourceWithProductName(String productName) throws SQLException { + DataSource dataSource = mock(DataSource.class); + Connection connection = mock(Connection.class); + given(dataSource.getConnection()).willReturn(connection); + DatabaseMetaData metadata = mock(DatabaseMetaData.class); + given(connection.getMetaData()).willReturn(metadata); + given(metadata.getDatabaseProductName()).willReturn(productName); + return dataSource; + } + +}