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 index a5279ecb45bd..75838458b41a 100644 --- 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 @@ -17,10 +17,12 @@ package org.springframework.boot.autoconfigure.session; import java.util.List; +import java.util.Objects; import javax.sql.DataSource; import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; @@ -38,6 +40,8 @@ */ public class JdbcSessionDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { + private JdbcSessionProperties properties; + /** * Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance. * @param dataSource the Spring Session JDBC data source @@ -46,6 +50,7 @@ public class JdbcSessionDataSourceScriptDatabaseInitializer extends DataSourceSc */ public JdbcSessionDataSourceScriptDatabaseInitializer(DataSource dataSource, JdbcSessionProperties properties) { this(dataSource, getSettings(dataSource, properties)); + this.properties = properties; } /** @@ -77,6 +82,34 @@ static DatabaseInitializationSettings getSettings(DataSource dataSource, JdbcSes return settings; } + @Override + protected void runScripts(Scripts scripts) { + validateConfiguration(); + super.runScripts(scripts); + } + + void validateConfiguration() { + if (properties == null) return; // cannot validate without this + JdbcSessionProperties defaults = new JdbcSessionProperties(); + boolean willHappen = switch (properties.getInitializeSchema()) { + case ALWAYS -> true; + case NEVER -> false; + case EMBEDDED -> isEmbeddedDatabase(); + }; + boolean tableNameChanged = !Objects.equals(defaults.getTableName(), properties.getTableName()); + boolean schemaUnchanged = Objects.equals(defaults.getSchema(), properties.getSchema()); + + if (willHappen && tableNameChanged && schemaUnchanged) { + String name = "spring.session.jdbc.schema"; + String value = properties.getSchema(); + String reason = "When JDBC Session database initialization will take place " + + "(spring.session.jdbc.initialize-schema = " + properties.getInitializeSchema() + "), " + + "and the table name is not the default value (" + properties.getTableName() + "), " + + "the schema must be a custom schema to match the specified table name."; + throw new InvalidConfigurationPropertyValueException(name, value, reason); + } + } + private static List resolveSchemaLocations(DataSource dataSource, JdbcSessionProperties properties) { PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MARIADB, "mysql"); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializerTests.java index 3b78e05e732a..b7beb10d250c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializerTests.java @@ -20,9 +20,12 @@ import org.junit.jupiter.api.Test; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.boot.sql.init.DatabaseInitializationSettings; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.mockito.BDDMockito.then; import static org.mockito.Mockito.mock; @@ -45,4 +48,29 @@ void getSettingsWithPlatformDoesNotTouchDataSource() { then(dataSource).shouldHaveNoInteractions(); } + @Test + void test_validateConfigurationThrowsForInvalidConfiguration() { + DataSource dataSource = mock(DataSource.class); + JdbcSessionProperties properties = new JdbcSessionProperties(); + properties.setPlatform("mysql"); + JdbcSessionDataSourceScriptDatabaseInitializer initializer = + new JdbcSessionDataSourceScriptDatabaseInitializer(dataSource, properties) { + @Override + protected boolean isEmbeddedDatabase() { + return false; + } + }; + + assertThatCode(initializer::validateConfiguration).doesNotThrowAnyException(); + + properties.setInitializeSchema(DatabaseInitializationMode.ALWAYS); + assertThatCode(initializer::validateConfiguration).doesNotThrowAnyException(); + + properties.setTableName(properties.getTableName() + "_CUSTOM"); + assertThatThrownBy(initializer::validateConfiguration).message().isNotBlank(); + + properties.setSchema(properties.getSchema() + ".different.sql"); + assertThatCode(initializer::validateConfiguration).doesNotThrowAnyException(); + } + }