From 674b01cb06ea40f007aea6cf2f491daa7f6c7f60 Mon Sep 17 00:00:00 2001 From: bono007 Date: Sun, 7 Feb 2021 16:02:21 -0600 Subject: [PATCH 1/2] Take JPA database action into account when setting ddlAuto See gh-25129 --- .../jpa/DataSourceInitializedPublisher.java | 3 +- .../orm/jpa/HibernateProperties.java | 4 ++ .../HibernateJpaAutoConfigurationTests.java | 45 +++++++++++++++++++ .../orm/jpa/HibernatePropertiesTests.java | 14 ++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java index b935b6d0974..76a4a4ee5da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java @@ -129,7 +129,8 @@ class DataSourceInitializedPublisher implements BeanPostProcessor { : "none"); Map hibernate = this.hibernateProperties.determineHibernateProperties( this.jpaProperties.getProperties(), new HibernateSettings().ddlAuto(defaultDdlAuto)); - return hibernate.containsKey("hibernate.hbm2ddl.auto"); + return hibernate.containsKey("hibernate.hbm2ddl.auto") || !hibernate + .getOrDefault("javax.persistence.schema-generation.database.action", "none").equals("none"); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java index 208c9baa492..b7e95d95029 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -35,6 +35,7 @@ import org.springframework.util.StringUtils; * Configuration properties for Hibernate. * * @author Stephane Nicoll + * @author Chris Bono * @since 2.1.0 * @see JpaProperties */ @@ -129,6 +130,9 @@ public class HibernateProperties { } private String determineDdlAuto(Map existing, Supplier defaultDdlAuto) { + if (existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION) != null) { + return null; + } String ddlAuto = existing.get(AvailableSettings.HBM2DDL_AUTO); if (ddlAuto != null) { return ddlAuto; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index 484a4677873..252fc760d22 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -91,6 +91,7 @@ import static org.mockito.Mockito.mock; * @author Andy Wilkinson * @author Kazuki Shimizu * @author Stephane Nicoll + * @author Chris Bono */ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTests { @@ -371,6 +372,50 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes .run((context) -> assertThat(context).doesNotHaveBean(City.class)); } + @Test + void dataSourceSchemaCreatedEventFiredWhenDdlAutoPropertyIsSet() { + dataSourceSchemaCreatedEventFired("spring.jpa.hibernate.ddl-auto:create-drop", true); + } + + @Test + void dataSourceSchemaCreatedEventNotFiredWhenDdlAutoPropertyIsSetToNone() { + dataSourceSchemaCreatedEventFired("spring.jpa.hibernate.ddl-auto:none", false); + } + + @Test + void dataSourceSchemaCreatedEventFiredWhenHibernateSpecificDdlAutoPropertyIsSet() { + dataSourceSchemaCreatedEventFired("spring.jpa.properties.hibernate.hbm2ddl.auto=create", true); + } + + @Test + void dataSourceSchemaCreatedEventNotFiredWhenHibernateSpecificDdlAutoPropertyIsSetToNone() { + dataSourceSchemaCreatedEventFired("spring.jpa.properties.hibernate.hbm2ddl.auto=none", false); + } + + @Test + void dataSourceSchemaCreatedEventFiredWhenJpaDbActionPropertyIsSet() { + dataSourceSchemaCreatedEventFired( + "spring.jpa.properties.javax.persistence.schema-generation.database.action=drop-and-create", true); + } + + @Test + void dataSourceSchemaCreatedEventNotFiredWhenJpaDbActionPropertyIsSetToNone() { + dataSourceSchemaCreatedEventFired( + "spring.jpa.properties.javax.persistence.schema-generation.database.action=none", false); + } + + private void dataSourceSchemaCreatedEventFired(String schemaGenerationPropertyWithValue, + boolean expectEventToBeFired) { + contextRunner().withUserConfiguration(JpaUsingApplicationListenerConfiguration.class) + .withPropertyValues("spring.datasource.initialization-mode=never", schemaGenerationPropertyWithValue) + .run((context) -> { + assertThat(context).hasNotFailed(); + assertThat(context.getBean(EventCapturingApplicationListener.class).events.stream() + .filter(DataSourceSchemaCreatedEvent.class::isInstance)) + .hasSize(expectEventToBeFired ? 1 : 0); + }); + } + @Test void withSyncBootstrappingAnApplicationListenerThatUsesJpaDoesNotTriggerABeanCurrentlyInCreationException() { contextRunner().withUserConfiguration(JpaUsingApplicationListenerConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java index b58da5f8d63..efb73dadcf3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java @@ -44,6 +44,7 @@ import static org.mockito.Mockito.verify; * * @author Stephane Nicoll * @author Artsiom Yudovin + * @author Chris Bono */ class HibernatePropertiesTests { @@ -135,6 +136,19 @@ class HibernatePropertiesTests { .run(assertDefaultDdlAutoNotInvoked("create")); } + @Test + void defaultDdlAutoIsNotInvokedAndDdlAutoIsNotSetIfJpaDbActionPropertyIsSet() { + this.contextRunner + .withPropertyValues( + "spring.jpa.properties.javax.persistence.schema-generation.database.action=drop-and-create") + .run(assertHibernateProperties((hibernateProperties) -> { + assertThat(hibernateProperties).doesNotContainKey(AvailableSettings.HBM2DDL_AUTO); + assertThat(hibernateProperties).containsEntry(AvailableSettings.HBM2DDL_DATABASE_ACTION, + "drop-and-create"); + verify(this.ddlAutoSupplier, never()).get(); + })); + } + private ContextConsumer assertDefaultDdlAutoNotInvoked(String expectedDdlAuto) { return assertHibernateProperties((hibernateProperties) -> { assertThat(hibernateProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, expectedDdlAuto); From c2f452a87a3a8a8289401d0642d994b555791106 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 22 Mar 2021 13:50:40 +0100 Subject: [PATCH 2/2] Polish "Take JPA database action into account when setting ddlAuto" See gh-25129 --- .../orm/jpa/HibernateProperties.java | 11 +-- .../HibernateJpaAutoConfigurationTests.java | 70 ++++++++++++------- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java index b7e95d95029..c8c5e2bd421 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -130,14 +130,17 @@ public class HibernateProperties { } private String determineDdlAuto(Map existing, Supplier defaultDdlAuto) { - if (existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION) != null) { - return null; - } String ddlAuto = existing.get(AvailableSettings.HBM2DDL_AUTO); if (ddlAuto != null) { return ddlAuto; } - return (this.ddlAuto != null) ? this.ddlAuto : defaultDdlAuto.get(); + if (this.ddlAuto != null) { + return this.ddlAuto; + } + if (existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION) != null) { + return null; + } + return defaultDdlAuto.get(); } public static class Naming { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index 252fc760d22..aaf0d64a256 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -373,47 +373,65 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes } @Test - void dataSourceSchemaCreatedEventFiredWhenDdlAutoPropertyIsSet() { - dataSourceSchemaCreatedEventFired("spring.jpa.hibernate.ddl-auto:create-drop", true); + void vendorPropertiesWithEmbeddedDatabaseAndNoDdlProperty() { + contextRunner().run(vendorProperties((vendorProperties) -> { + assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.HBM2DDL_DATABASE_ACTION); + assertThat(vendorProperties.get(AvailableSettings.HBM2DDL_AUTO)).isEqualTo("create-drop"); + })); } @Test - void dataSourceSchemaCreatedEventNotFiredWhenDdlAutoPropertyIsSetToNone() { - dataSourceSchemaCreatedEventFired("spring.jpa.hibernate.ddl-auto:none", false); + void vendorPropertiesWithDdlAutoPropertyIsSet() { + contextRunner().withPropertyValues("spring.jpa.hibernate.ddl-auto=update") + .run(vendorProperties((vendorProperties) -> { + assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.HBM2DDL_DATABASE_ACTION); + assertThat(vendorProperties.get(AvailableSettings.HBM2DDL_AUTO)).isEqualTo("update"); + })); } @Test - void dataSourceSchemaCreatedEventFiredWhenHibernateSpecificDdlAutoPropertyIsSet() { - dataSourceSchemaCreatedEventFired("spring.jpa.properties.hibernate.hbm2ddl.auto=create", true); + void vendorPropertiesWithDdlAutoPropertyAndHibernatePropertiesAreSet() { + contextRunner() + .withPropertyValues("spring.jpa.hibernate.ddl-auto=update", + "spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop") + .run(vendorProperties((vendorProperties) -> { + assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.HBM2DDL_DATABASE_ACTION); + assertThat(vendorProperties.get(AvailableSettings.HBM2DDL_AUTO)).isEqualTo("create-drop"); + })); } @Test - void dataSourceSchemaCreatedEventNotFiredWhenHibernateSpecificDdlAutoPropertyIsSetToNone() { - dataSourceSchemaCreatedEventFired("spring.jpa.properties.hibernate.hbm2ddl.auto=none", false); + void vendorPropertiesWithDdlAutoPropertyIsSetToNone() { + contextRunner().withPropertyValues("spring.jpa.hibernate.ddl-auto=none") + .run(vendorProperties((vendorProperties) -> assertThat(vendorProperties).doesNotContainKeys( + AvailableSettings.HBM2DDL_DATABASE_ACTION, AvailableSettings.HBM2DDL_AUTO))); } @Test - void dataSourceSchemaCreatedEventFiredWhenJpaDbActionPropertyIsSet() { - dataSourceSchemaCreatedEventFired( - "spring.jpa.properties.javax.persistence.schema-generation.database.action=drop-and-create", true); + void vendorPropertiesWhenJpaDdlActionIsSet() { + contextRunner() + .withPropertyValues("spring.jpa.properties.javax.persistence.schema-generation.database.action=create") + .run(vendorProperties((vendorProperties) -> { + assertThat(vendorProperties.get(AvailableSettings.HBM2DDL_DATABASE_ACTION)).isEqualTo("create"); + assertThat(vendorProperties).doesNotContainKeys(AvailableSettings.HBM2DDL_AUTO); + })); } @Test - void dataSourceSchemaCreatedEventNotFiredWhenJpaDbActionPropertyIsSetToNone() { - dataSourceSchemaCreatedEventFired( - "spring.jpa.properties.javax.persistence.schema-generation.database.action=none", false); - } - - private void dataSourceSchemaCreatedEventFired(String schemaGenerationPropertyWithValue, - boolean expectEventToBeFired) { - contextRunner().withUserConfiguration(JpaUsingApplicationListenerConfiguration.class) - .withPropertyValues("spring.datasource.initialization-mode=never", schemaGenerationPropertyWithValue) - .run((context) -> { - assertThat(context).hasNotFailed(); - assertThat(context.getBean(EventCapturingApplicationListener.class).events.stream() - .filter(DataSourceSchemaCreatedEvent.class::isInstance)) - .hasSize(expectEventToBeFired ? 1 : 0); - }); + void vendorPropertiesWhenBothDdlAutoPropertiesAreSet() { + contextRunner() + .withPropertyValues("spring.jpa.properties.javax.persistence.schema-generation.database.action=create", + "spring.jpa.hibernate.ddl-auto=create-only") + .run(vendorProperties((vendorProperties) -> { + assertThat(vendorProperties.get(AvailableSettings.HBM2DDL_DATABASE_ACTION)).isEqualTo("create"); + assertThat(vendorProperties.get(AvailableSettings.HBM2DDL_AUTO)).isEqualTo("create-only"); + })); + } + + private ContextConsumer vendorProperties( + Consumer> vendorProperties) { + return (context) -> vendorProperties + .accept(context.getBean(HibernateJpaConfiguration.class).getVendorProperties()); } @Test