25
25
import jakarta .persistence .metamodel .Metamodel ;
26
26
import jakarta .persistence .metamodel .SingularAttribute ;
27
27
28
+ import java .lang .reflect .Proxy ;
28
29
import java .util .Collection ;
29
30
import java .util .Collections ;
30
31
import java .util .List ;
31
32
import java .util .NoSuchElementException ;
32
33
import java .util .Set ;
33
34
import java .util .function .LongSupplier ;
35
+ import java .util .stream .Stream ;
34
36
35
37
import org .eclipse .persistence .config .QueryHints ;
36
38
import org .eclipse .persistence .jpa .JpaQuery ;
41
43
import org .hibernate .query .SelectionQuery ;
42
44
import org .jspecify .annotations .Nullable ;
43
45
46
+ import org .springframework .aop .framework .AopProxyUtils ;
47
+ import org .springframework .aop .support .AopUtils ;
44
48
import org .springframework .data .util .CloseableIterator ;
45
49
import org .springframework .transaction .support .TransactionSynchronizationManager ;
46
50
import org .springframework .util .Assert ;
56
60
* @author Jens Schauder
57
61
* @author Greg Turnquist
58
62
* @author Yuriy Tsarkov
59
- * @author Ariel Morelli Andres (Atlassian US, Inc.)
63
+ * @author Ariel Morelli Andres
60
64
*/
61
65
public enum PersistenceProvider implements QueryExtractor , ProxyIdAccessor , QueryComment {
62
66
63
67
/**
64
68
* 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>
70
69
*/
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 )) {
75
72
76
73
@ Override
77
74
public @ Nullable String extractQueryString (Object query ) {
@@ -136,9 +133,7 @@ public long getResultCount(Query resultQuery, LongSupplier countSupplier) {
136
133
/**
137
134
* EclipseLink persistence provider.
138
135
*/
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 )) {
142
137
143
138
@ Override
144
139
public String extractQueryString (Object query ) {
@@ -180,8 +175,7 @@ public String getCommentHintValue(String comment) {
180
175
/**
181
176
* Unknown special provider. Use standard JPA.
182
177
*/
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 ()) {
185
179
186
180
@ Override
187
181
public @ Nullable String extractQueryString (Object query ) {
@@ -231,8 +225,7 @@ public boolean shouldUseAccessorFor(Object entity) {
231
225
private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
232
226
233
227
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 ;
236
229
private final Iterable <String > metamodelClassNames ;
237
230
238
231
private final boolean present ;
@@ -242,37 +235,15 @@ public boolean shouldUseAccessorFor(Object entity) {
242
235
*
243
236
* @param entityManagerFactoryClassNames the names of the provider specific
244
237
* {@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.
248
240
*/
249
- PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
250
- Iterable <String > metamodelClassNames ) {
241
+ PersistenceProvider (Collection <String > entityManagerFactoryClassNames , Collection <String > metamodelClassNames ) {
251
242
252
243
this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
253
- this .entityManagerClassNames = entityManagerClassNames ;
254
244
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 ()));
276
247
}
277
248
278
249
/**
@@ -288,32 +259,23 @@ private static PersistenceProvider cacheAndReturn(Class<?> type, PersistenceProv
288
259
}
289
260
290
261
/**
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
292
264
* 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()}.
293
269
*
294
270
* @param em must not be {@literal null}.
295
271
* @return will never be {@literal null}.
272
+ * @see org.springframework.orm.jpa.SharedEntityManagerCreator
296
273
*/
297
274
public static PersistenceProvider fromEntityManager (EntityManager em ) {
298
275
299
276
Assert .notNull (em , "EntityManager must not be null" );
300
277
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 ());
317
279
}
318
280
319
281
/**
@@ -322,12 +284,24 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
322
284
*
323
285
* @param emf must not be {@literal null}.
324
286
* @return will never be {@literal null}.
287
+ * @since 3.5.1
325
288
*/
326
289
public static PersistenceProvider fromEntityManagerFactory (EntityManagerFactory emf ) {
327
290
328
291
Assert .notNull (emf , "EntityManagerFactory must not be null" );
329
292
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 ();
331
305
PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
332
306
333
307
if (cachedProvider != null ) {
@@ -336,8 +310,7 @@ public static PersistenceProvider fromEntityManagerFactory(EntityManagerFactory
336
310
337
311
for (PersistenceProvider provider : ALL ) {
338
312
for (String emfClassName : provider .entityManagerFactoryClassNames ) {
339
- if (isOfType (emf .getPersistenceUnitUtil (), emfClassName ,
340
- emf .getPersistenceUnitUtil ().getClass ().getClassLoader ())) {
313
+ if (isOfType (unwrapped , emfClassName , unwrapped .getClass ().getClassLoader ())) {
341
314
return cacheAndReturn (entityManagerType , provider );
342
315
}
343
316
}
@@ -445,16 +418,14 @@ interface Constants {
445
418
String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
446
419
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager" ;
447
420
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" ;
450
422
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
423
+ String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
451
424
452
425
// 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" ;
456
428
String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
457
- String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
458
429
459
430
}
460
431
0 commit comments