From 4c8f1910c82c340135082f3947f7dd9b611d6849 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 23 May 2023 20:33:19 +0200 Subject: [PATCH] Align HibernateJpaVendorAdapter with Hibernate ORM 6.2 Includes documentation and test revisions. Closes gh-30288 --- .../ROOT/pages/data-access/orm/hibernate.adoc | 12 +++- .../orm/jpa/vendor/HibernateJpaDialect.java | 2 +- .../jpa/vendor/HibernateJpaVendorAdapter.java | 56 +++++++++++++------ ...SpringHibernateJpaPersistenceProvider.java | 4 +- ...eEntityManagerFactoryIntegrationTests.java | 19 +------ .../support/PersistenceInjectionTests.java | 4 +- .../orm/jpa/hibernate/hibernate-manager.xml | 4 +- 7 files changed, 58 insertions(+), 43 deletions(-) diff --git a/framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc b/framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc index 883aafc3b0d..a782b9165e0 100644 --- a/framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc +++ b/framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc @@ -8,10 +8,16 @@ implementations and transaction demarcation. Most of these patterns can be direc translated to all other supported ORM tools. The later sections in this chapter then cover the other ORM technologies and show brief examples. -NOTE: As of Spring Framework 5.3, Spring requires Hibernate ORM 5.2+ for Spring's +[NOTE] +==== +As of Spring Framework 6.0, Spring requires Hibernate ORM 5.5+ for Spring's `HibernateJpaVendorAdapter` as well as for a native Hibernate `SessionFactory` setup. -It is strongly recommended to go with Hibernate ORM 5.4 for a newly started application. -For use with `HibernateJpaVendorAdapter`, Hibernate Search needs to be upgraded to 5.11.6. +We recommend Hibernate ORM 5.6 as the last feature branch in that Hibernate generation. + +Hibernate ORM 6.x is only supported as a JPA provider (`HibernateJpaVendorAdapter`). +Plain `SessionFactory` setup with the `orm.hibernate5` package is not supported anymore. +We recommend Hibernate ORM 6.1/6.2 with JPA-style setup for new development projects. +==== [[orm-session-factory-setup]] diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java index b561140b570..76f7304e308 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java @@ -74,7 +74,7 @@ import org.springframework.util.ReflectionUtils; /** * {@link org.springframework.orm.jpa.JpaDialect} implementation for Hibernate. - * Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1. + * Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1/6.2. * * @author Juergen Hoeller * @author Costin Leau diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java index 6bc9a75a77e..6cd463dcdb7 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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,6 +28,7 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.DerbyTenSevenDialect; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.HANAColumnStoreDialect; @@ -36,15 +37,17 @@ import org.hibernate.dialect.Informix10Dialect; import org.hibernate.dialect.MySQL57Dialect; import org.hibernate.dialect.Oracle12cDialect; import org.hibernate.dialect.PostgreSQL95Dialect; +import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.SQLServer2012Dialect; import org.hibernate.dialect.SybaseDialect; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.springframework.lang.Nullable; +import org.springframework.util.ClassUtils; /** * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate. - * Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1. + * Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1/6.2. * *

Exposes Hibernate's persistence provider and Hibernate's Session as extended * EntityManager interface, and adapts {@link AbstractJpaVendorAdapter}'s common @@ -69,6 +72,9 @@ import org.springframework.lang.Nullable; */ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { + private static final boolean oldDialectsPresent = ClassUtils.isPresent( + "org.hibernate.dialect.PostgreSQL95Dialect", HibernateJpaVendorAdapter.class.getClassLoader()); + private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect(); private final PersistenceProvider persistenceProvider; @@ -167,22 +173,40 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { * @param database the target database * @return the Hibernate database dialect class, or {@code null} if none found */ + @SuppressWarnings("deprecation") // for Derby/PostgreSQLDialect on Hibernate 6.2 @Nullable protected Class determineDatabaseDialectClass(Database database) { - return switch (database) { - case DB2 -> DB2Dialect.class; - case DERBY -> DerbyTenSevenDialect.class; - case H2 -> H2Dialect.class; - case HANA -> HANAColumnStoreDialect.class; - case HSQL -> HSQLDialect.class; - case INFORMIX -> Informix10Dialect.class; - case MYSQL -> MySQL57Dialect.class; - case ORACLE -> Oracle12cDialect.class; - case POSTGRESQL -> PostgreSQL95Dialect.class; - case SQL_SERVER -> SQLServer2012Dialect.class; - case SYBASE -> SybaseDialect.class; - default -> null; - }; + if (oldDialectsPresent) { // Hibernate <6.2 + return switch (database) { + case DB2 -> DB2Dialect.class; + case DERBY -> DerbyTenSevenDialect.class; + case H2 -> H2Dialect.class; + case HANA -> HANAColumnStoreDialect.class; + case HSQL -> HSQLDialect.class; + case INFORMIX -> Informix10Dialect.class; + case MYSQL -> MySQL57Dialect.class; + case ORACLE -> Oracle12cDialect.class; + case POSTGRESQL -> PostgreSQL95Dialect.class; + case SQL_SERVER -> SQLServer2012Dialect.class; + case SYBASE -> SybaseDialect.class; + default -> null; + }; + } + else { // Hibernate 6.2 aligned + return switch (database) { + case DB2 -> DB2Dialect.class; + case DERBY -> DerbyDialect.class; + case H2 -> H2Dialect.class; + case HANA -> HANAColumnStoreDialect.class; + case HSQL -> HSQLDialect.class; + case MYSQL -> MySQL57Dialect.class; + case ORACLE -> Oracle12cDialect.class; + case POSTGRESQL -> PostgreSQLDialect.class; + case SQL_SERVER -> SQLServer2012Dialect.class; + case SYBASE -> SybaseDialect.class; + default -> null; + }; + } } @Override diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/SpringHibernateJpaPersistenceProvider.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/SpringHibernateJpaPersistenceProvider.java index 01aaff9c5a9..511d55f0dd7 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/SpringHibernateJpaPersistenceProvider.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/SpringHibernateJpaPersistenceProvider.java @@ -43,6 +43,7 @@ import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo; * @since 4.1 * @see Configuration#addPackage */ +@SuppressWarnings("removal") // for Environment properties on Hibernate 6.2 class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider { static { @@ -53,7 +54,7 @@ class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider } @Override - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "unchecked"}) // on Hibernate 6 public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) { final List mergedClassesAndPackages = new ArrayList<>(info.getManagedClassNames()); if (info instanceof SmartPersistenceUnitInfo smartInfo) { @@ -65,7 +66,6 @@ class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider public List getManagedClassNames() { return mergedClassesAndPackages; } - @Override public void pushClassTransformer(EnhancementContext enhancementContext) { if (!NativeDetector.inNativeImage()) { diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java index 00963e101ef..b0818fffc3a 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java @@ -49,32 +49,19 @@ public class HibernateEntityManagerFactoryIntegrationTests extends AbstractConta @Test public void testCanCastNativeEntityManagerFactoryToHibernateEntityManagerFactoryImpl() { EntityManagerFactoryInfo emfi = (EntityManagerFactoryInfo) entityManagerFactory; - boolean condition1 = emfi.getNativeEntityManagerFactory() instanceof org.hibernate.jpa.HibernateEntityManagerFactory; - assertThat(condition1).isTrue(); - // as of Hibernate 5.2 - boolean condition = emfi.getNativeEntityManagerFactory() instanceof SessionFactory; - assertThat(condition).isTrue(); + assertThat(emfi.getNativeEntityManagerFactory() instanceof SessionFactory).isTrue(); } @Test public void testCanCastSharedEntityManagerProxyToHibernateEntityManager() { - boolean condition1 = sharedEntityManager instanceof org.hibernate.jpa.HibernateEntityManager; - assertThat(condition1).isTrue(); - // as of Hibernate 5.2 - boolean condition = ((EntityManagerProxy) sharedEntityManager).getTargetEntityManager() instanceof Session; - assertThat(condition).isTrue(); + assertThat(((EntityManagerProxy) sharedEntityManager).getTargetEntityManager() instanceof Session).isTrue(); } @Test public void testCanUnwrapAopProxy() { EntityManager em = entityManagerFactory.createEntityManager(); EntityManager proxy = ProxyFactory.getProxy(EntityManager.class, new SingletonTargetSource(em)); - boolean condition = em instanceof org.hibernate.jpa.HibernateEntityManager; - assertThat(condition).isTrue(); - boolean condition1 = proxy instanceof org.hibernate.jpa.HibernateEntityManager; - assertThat(condition1).isFalse(); - assertThat(proxy.unwrap(org.hibernate.jpa.HibernateEntityManager.class)).isNotNull(); - assertThat(proxy.unwrap(org.hibernate.jpa.HibernateEntityManager.class)).isSameAs(em); + assertThat(proxy.unwrap(Session.class)).isSameAs(em); assertThat(proxy.getDelegate()).isSameAs(em.getDelegate()); } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java index 8d287545b7f..c840a8c8f63 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceInjectionTests.java @@ -30,6 +30,7 @@ import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContextType; import jakarta.persistence.PersistenceProperty; import jakarta.persistence.PersistenceUnit; +import org.hibernate.Session; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.FactoryBean; @@ -700,8 +701,7 @@ public class PersistenceInjectionTests extends AbstractEntityManagerFactoryBeanT public static class DefaultVendorSpecificPrivatePersistenceContextField { @PersistenceContext - @SuppressWarnings("deprecation") - private org.hibernate.ejb.HibernateEntityManager em; + private Session em; } diff --git a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml index 0915a4eea9f..114d495e08c 100644 --- a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml +++ b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/hibernate-manager.xml @@ -28,9 +28,7 @@ - - - +