2525import jakarta .persistence .metamodel .Metamodel ;
2626import jakarta .persistence .metamodel .SingularAttribute ;
2727
28+ import java .lang .reflect .Proxy ;
2829import java .util .Collection ;
2930import java .util .Collections ;
3031import java .util .List ;
3132import java .util .NoSuchElementException ;
3233import java .util .Set ;
3334import java .util .function .LongSupplier ;
35+ import java .util .stream .Stream ;
3436
3537import org .eclipse .persistence .config .QueryHints ;
3638import org .eclipse .persistence .jpa .JpaQuery ;
4143import org .hibernate .query .SelectionQuery ;
4244import org .jspecify .annotations .Nullable ;
4345
46+ import org .springframework .aop .framework .AopProxyUtils ;
47+ import org .springframework .aop .support .AopUtils ;
4448import org .springframework .data .util .CloseableIterator ;
4549import org .springframework .transaction .support .TransactionSynchronizationManager ;
4650import org .springframework .util .Assert ;
5660 * @author Jens Schauder
5761 * @author Greg Turnquist
5862 * @author Yuriy Tsarkov
59- * @author Ariel Morelli Andres (Atlassian US, Inc.)
63+ * @author Ariel Morelli Andres
6064 */
6165public enum PersistenceProvider implements QueryExtractor , ProxyIdAccessor , QueryComment {
6266
6367 /**
6468 * Hibernate persistence provider.
65- * <p>
66- * Since Hibernate 4.3 the location of the HibernateEntityManager moved to the org.hibernate.jpa package. In order to
67- * support both locations we interpret both classnames as a Hibernate {@code PersistenceProvider}.
68- *
69- * @see <a href="https://github.com/spring-projects/spring-data-jpa/issues/846">DATAJPA-444</a>
7069 */
71- HIBERNATE (//
72- Collections .singletonList (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
73- Collections .singletonList (HIBERNATE_ENTITY_MANAGER_INTERFACE ), //
74- Collections .singletonList (HIBERNATE_JPA_METAMODEL_TYPE )) {
70+ HIBERNATE (List .of (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
71+ List .of (HIBERNATE_JPA_METAMODEL_TYPE )) {
7572
7673 @ Override
7774 public @ Nullable String extractQueryString (Object query ) {
@@ -136,9 +133,7 @@ public long getResultCount(Query resultQuery, LongSupplier countSupplier) {
136133 /**
137134 * EclipseLink persistence provider.
138135 */
139- ECLIPSELINK (List .of (ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 , ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 ),
140- Collections .singleton (ECLIPSELINK_ENTITY_MANAGER_INTERFACE ),
141- Collections .singleton (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
136+ ECLIPSELINK (List .of (ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE ), List .of (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
142137
143138 @ Override
144139 public String extractQueryString (Object query ) {
@@ -180,8 +175,7 @@ public String getCommentHintValue(String comment) {
180175 /**
181176 * Unknown special provider. Use standard JPA.
182177 */
183- GENERIC_JPA (Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ),
184- Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ), Collections .emptySet ()) {
178+ GENERIC_JPA (List .of (GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE ), Collections .emptySet ()) {
185179
186180 @ Override
187181 public @ Nullable String extractQueryString (Object query ) {
@@ -231,8 +225,7 @@ public boolean shouldUseAccessorFor(Object entity) {
231225 private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
232226
233227 private static final ConcurrentReferenceHashMap <Class <?>, PersistenceProvider > CACHE = new ConcurrentReferenceHashMap <>();
234- private final Iterable <String > entityManagerFactoryClassNames ;
235- private final Iterable <String > entityManagerClassNames ;
228+ final Iterable <String > entityManagerFactoryClassNames ;
236229 private final Iterable <String > metamodelClassNames ;
237230
238231 private final boolean present ;
@@ -242,37 +235,15 @@ public boolean shouldUseAccessorFor(Object entity) {
242235 *
243236 * @param entityManagerFactoryClassNames the names of the provider specific
244237 * {@link jakarta.persistence.EntityManagerFactory} implementations. Must not be {@literal null} or empty.
245- * @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
246- * be {@literal null} or empty.
247- * @param metamodelClassNames must not be {@literal null}.
238+ * @param metamodelClassNames the names of the provider specific {@link Metamodel} implementations. Must not be
239+ * {@literal null} or empty.
248240 */
249- PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
250- Iterable <String > metamodelClassNames ) {
241+ PersistenceProvider (Collection <String > entityManagerFactoryClassNames , Collection <String > metamodelClassNames ) {
251242
252243 this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
253- this .entityManagerClassNames = entityManagerClassNames ;
254244 this .metamodelClassNames = metamodelClassNames ;
255-
256- boolean present = false ;
257- for (String emfClassName : entityManagerFactoryClassNames ) {
258-
259- if (ClassUtils .isPresent (emfClassName , PersistenceProvider .class .getClassLoader ())) {
260- present = true ;
261- break ;
262- }
263- }
264-
265- if (!present ) {
266- for (String entityManagerClassName : entityManagerClassNames ) {
267-
268- if (ClassUtils .isPresent (entityManagerClassName , PersistenceProvider .class .getClassLoader ())) {
269- present = true ;
270- break ;
271- }
272- }
273- }
274-
275- this .present = present ;
245+ this .present = Stream .concat (entityManagerFactoryClassNames .stream (), metamodelClassNames .stream ())
246+ .anyMatch (it -> ClassUtils .isPresent (it , PersistenceProvider .class .getClassLoader ()));
276247 }
277248
278249 /**
@@ -288,32 +259,23 @@ private static PersistenceProvider cacheAndReturn(Class<?> type, PersistenceProv
288259 }
289260
290261 /**
291- * Determines the {@link PersistenceProvider} from the given {@link EntityManager}. If no special one can be
262+ * Determines the {@link PersistenceProvider} from the given {@link EntityManager} by introspecting
263+ * {@link EntityManagerFactory} via {@link EntityManager#getEntityManagerFactory()}. If no special one can be
292264 * determined {@link #GENERIC_JPA} will be returned.
265+ * <p>
266+ * This method avoids {@link EntityManager} initialization when using
267+ * {@link org.springframework.orm.jpa.SharedEntityManagerCreator} by accessing
268+ * {@link EntityManager#getEntityManagerFactory()}.
293269 *
294270 * @param em must not be {@literal null}.
295271 * @return will never be {@literal null}.
272+ * @see org.springframework.orm.jpa.SharedEntityManagerCreator
296273 */
297274 public static PersistenceProvider fromEntityManager (EntityManager em ) {
298275
299276 Assert .notNull (em , "EntityManager must not be null" );
300277
301- Class <?> entityManagerType = em .getDelegate ().getClass ();
302- PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
303-
304- if (cachedProvider != null ) {
305- return cachedProvider ;
306- }
307-
308- for (PersistenceProvider provider : ALL ) {
309- for (String entityManagerClassName : provider .entityManagerClassNames ) {
310- if (isEntityManagerOfType (em , entityManagerClassName )) {
311- return cacheAndReturn (entityManagerType , provider );
312- }
313- }
314- }
315-
316- return cacheAndReturn (entityManagerType , GENERIC_JPA );
278+ return fromEntityManagerFactory (em .getEntityManagerFactory ());
317279 }
318280
319281 /**
@@ -322,12 +284,24 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
322284 *
323285 * @param emf must not be {@literal null}.
324286 * @return will never be {@literal null}.
287+ * @since 3.5.1
325288 */
326289 public static PersistenceProvider fromEntityManagerFactory (EntityManagerFactory emf ) {
327290
328291 Assert .notNull (emf , "EntityManagerFactory must not be null" );
329292
330- Class <?> entityManagerType = emf .getPersistenceUnitUtil ().getClass ();
293+ EntityManagerFactory unwrapped = emf ;
294+
295+ while (Proxy .isProxyClass (unwrapped .getClass ()) || AopUtils .isAopProxy (unwrapped )) {
296+
297+ if (Proxy .isProxyClass (unwrapped .getClass ())) {
298+ unwrapped = unwrapped .unwrap (null );
299+ } else if (AopUtils .isAopProxy (unwrapped )) {
300+ unwrapped = (EntityManagerFactory ) AopProxyUtils .getSingletonTarget (unwrapped );
301+ }
302+ }
303+
304+ Class <?> entityManagerType = unwrapped .getClass ();
331305 PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
332306
333307 if (cachedProvider != null ) {
@@ -336,8 +310,7 @@ public static PersistenceProvider fromEntityManagerFactory(EntityManagerFactory
336310
337311 for (PersistenceProvider provider : ALL ) {
338312 for (String emfClassName : provider .entityManagerFactoryClassNames ) {
339- if (isOfType (emf .getPersistenceUnitUtil (), emfClassName ,
340- emf .getPersistenceUnitUtil ().getClass ().getClassLoader ())) {
313+ if (isOfType (unwrapped , emfClassName , unwrapped .getClass ().getClassLoader ())) {
341314 return cacheAndReturn (entityManagerType , provider );
342315 }
343316 }
@@ -445,16 +418,14 @@ interface Constants {
445418 String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
446419 String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager" ;
447420
448- String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate" ;
449- String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl" ;
421+ String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManagerFactory" ;
450422 String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
423+ String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
451424
452425 // needed as Spring only exposes that interface via the EM proxy
453- String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.jpa.internal.PersistenceUnitUtilImpl" ;
454- String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.engine.spi.SessionImplementor" ;
455-
426+ String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.SessionFactory" ;
427+ String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.Session" ;
456428 String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
457- String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
458429
459430 }
460431
0 commit comments