From 7ce1c673ff7f17c8dc2e688b5deb7fbebfcb4316 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 11 Nov 2021 09:09:54 -0600 Subject: [PATCH] JpaCompliance improvement --- .../boot/internal/BootstrapContextImpl.java | 2 +- .../org/hibernate/cfg/AvailableSettings.java | 18 +++ .../internal/MutableJpaComplianceImpl.java | 16 +++ .../jpa/compliance/JpaComplianceTests.java | 131 ++++++++++++++++++ .../orm/junit/ServiceRegistryScope.java | 11 ++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/JpaComplianceTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java index 4f20d78490..272f5d9b4d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java @@ -93,7 +93,7 @@ public class BootstrapContextImpl implements BootstrapContext { final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); - this.jpaCompliance = new MutableJpaComplianceImpl( configService.getSettings(), false ); + this.jpaCompliance = new MutableJpaComplianceImpl( configService.getSettings() ); this.scanOptions = new StandardScanOptions( (String) configService.getSettings().get( AvailableSettings.SCANNER_DISCOVERY ), false diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index ceaeb2bb1a..27044847ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -2186,6 +2186,24 @@ public interface AvailableSettings { */ String CRITERIA_VALUE_HANDLING_MODE = "hibernate.criteria.value_handling_mode"; + /** + * Allows setting default value for all {@link JpaCompliance} flags. Individual + * flags can still be overridden individually using its specific setting + * + * @see #JPA_TRANSACTION_COMPLIANCE + * @see #JPA_QUERY_COMPLIANCE + * @see #JPA_LIST_COMPLIANCE + * @see #JPA_ORDER_BY_MAPPING_COMPLIANCE + * @see #JPA_CLOSED_COMPLIANCE + * @see #JPA_PROXY_COMPLIANCE + * @see #JPA_CACHING_COMPLIANCE + * @see #JPA_ID_GENERATOR_GLOBAL_SCOPE_COMPLIANCE + * @see #JPA_LOAD_BY_ID_COMPLIANCE + * + * @since 6.0 + */ + String JPA_COMPLIANCE = "hibernate.jpa.compliance"; + /** * Should Hibernate's {@link Transaction} behave as * defined by the spec for JPA's {@link jakarta.persistence.EntityTransaction} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/MutableJpaComplianceImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/MutableJpaComplianceImpl.java index ba6cf9f9b2..fd26c19d14 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/MutableJpaComplianceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/MutableJpaComplianceImpl.java @@ -27,6 +27,22 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance { private boolean cachingCompliance; private boolean loadByIdCompliance; + public MutableJpaComplianceImpl(Map configurationSettings) { + this( + configurationSettings, + ConfigurationHelper.getBoolean( + AvailableSettings.JPA_COMPLIANCE, + configurationSettings, + false + ) + ); + } + + /** + * Generallythe + * @param configurationSettings + * @param jpaByDefault + */ @SuppressWarnings("ConstantConditions") public MutableJpaComplianceImpl(Map configurationSettings, boolean jpaByDefault) { final Object legacyQueryCompliance = configurationSettings.get( AvailableSettings.JPAQL_STRICT_COMPLIANCE ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/JpaComplianceTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/JpaComplianceTests.java new file mode 100644 index 0000000000..b1f5167b60 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/compliance/JpaComplianceTests.java @@ -0,0 +1,131 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.jpa.compliance; + +import java.util.Collections; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.jpa.internal.MutableJpaComplianceImpl; +import org.hibernate.jpa.spi.JpaCompliance; + +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +public class JpaComplianceTests { + @Test + public void testDefaultTrue() { + // MutableJpaComplianceImpl defaults its values based on the passed + // `jpaByDefault` (`true` here). ultimately we want to source this + // from `AvailableSettings#JPA_COMPLIANCE` + final MutableJpaComplianceImpl compliance = new MutableJpaComplianceImpl( Collections.emptyMap(), true ); + assertAll( compliance, true ); + } + + @Test + public void testDefaultFalse() { + // MutableJpaComplianceImpl defaults its values based on the passed + // `jpaByDefault` (`true` here). ultimately we want to source this + // from `AvailableSettings#JPA_COMPLIANCE` + final MutableJpaComplianceImpl compliance = new MutableJpaComplianceImpl( Collections.emptyMap(), false ); + assertAll( compliance, false ); + } + + private void assertAll(JpaCompliance compliance, boolean expected) { + assertThat( compliance.isJpaQueryComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaTransactionComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaClosedComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaListComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaOrderByMappingComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaProxyComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaCacheComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isGlobalGeneratorScopeEnabled() ).isEqualTo( expected ); + } + @Test + public void testDefaultTrueWithOverride() { + // MutableJpaComplianceImpl defaults its values based on the passed + // `jpaByDefault` (`true` here). ultimately we want to source this + // from `AvailableSettings#JPA_COMPLIANCE` + final MutableJpaComplianceImpl compliance = new MutableJpaComplianceImpl( Collections.emptyMap(), true ); + compliance.setQueryCompliance( false ); + assertOverridden( compliance, true ); + } + + @Test + public void testDefaultFalseWithOverride() { + // MutableJpaComplianceImpl defaults its values based on the passed + // `jpaByDefault` (`true` here). ultimately we want to source this + // from `AvailableSettings#JPA_COMPLIANCE` + final MutableJpaComplianceImpl compliance = new MutableJpaComplianceImpl( Collections.emptyMap(), false ); + compliance.setQueryCompliance( true ); + assertOverridden( compliance, false ); + } + + private void assertOverridden(MutableJpaComplianceImpl compliance, boolean expected) { + assertThat( compliance.isJpaQueryComplianceEnabled() ).isEqualTo( !expected ); + assertThat( compliance.isJpaTransactionComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaClosedComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaListComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaOrderByMappingComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaProxyComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isJpaCacheComplianceEnabled() ).isEqualTo( expected ); + assertThat( compliance.isGlobalGeneratorScopeEnabled() ).isEqualTo( expected ); + } + + @Test + public void testSettingTrue() { + ServiceRegistryScope.using( + () -> new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.JPA_COMPLIANCE, true ) + .build(), + (serviceRegistryScope) -> { + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( serviceRegistryScope.getRegistry() ) + .buildMetadata() + .buildSessionFactory(); + final JpaCompliance jpaCompliance = sessionFactory.getSessionFactoryOptions().getJpaCompliance(); + assertAll( jpaCompliance, true ); + } + ); + // MutableJpaComplianceImpl defaults its values based on the passed + // `jpaByDefault` (`true` here). ultimately we want to source this + // from `AvailableSettings#JPA_COMPLIANCE` + final MutableJpaComplianceImpl compliance = new MutableJpaComplianceImpl( Collections.emptyMap(), true ); + assertAll( compliance, true ); + } + + @Test + public void testSettingFalse() { + ServiceRegistryScope.using( + () -> new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.JPA_COMPLIANCE, false ) + .build(), + (serviceRegistryScope) -> { + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) new MetadataSources( serviceRegistryScope.getRegistry() ) + .buildMetadata() + .buildSessionFactory(); + final JpaCompliance jpaCompliance = sessionFactory.getSessionFactoryOptions().getJpaCompliance(); + assertAll( jpaCompliance, false ); + } + ); + + // MutableJpaComplianceImpl defaults its values based on the passed + // `jpaByDefault` (`true` here). ultimately we want to source this + // from `AvailableSettings#JPA_COMPLIANCE` + final MutableJpaComplianceImpl compliance = new MutableJpaComplianceImpl( Collections.emptyMap(), true ); + assertAll( compliance, true ); + } + + +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryScope.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryScope.java index c893fe3c11..0379a170a2 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryScope.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryScope.java @@ -8,6 +8,7 @@ package org.hibernate.testing.orm.junit; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.service.Service; @@ -16,6 +17,16 @@ import org.hibernate.service.Service; * @author Steve Ebersole */ public interface ServiceRegistryScope { + /** + * Generalized support for running exception-safe code using a ServiceRegistry to + * ensure proper shutdown + */ + static void using(Supplier ssrProducer, Consumer action) { + try (final StandardServiceRegistry ssr = ssrProducer.get()) { + action.accept( () -> ssr ); + } + } + StandardServiceRegistry getRegistry(); default void withService(Class role, Consumer action) {