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 ;
34
+ import java .util .function .LongSupplier ;
35
+ import java .util .stream .Stream ;
33
36
34
37
import org .eclipse .persistence .config .QueryHints ;
35
38
import org .eclipse .persistence .jpa .JpaQuery ;
38
41
import org .hibernate .ScrollableResults ;
39
42
import org .hibernate .proxy .HibernateProxy ;
40
43
44
+ import org .springframework .aop .framework .AopProxyUtils ;
45
+ import org .springframework .aop .support .AopUtils ;
41
46
import org .springframework .data .util .CloseableIterator ;
42
47
import org .springframework .lang .Nullable ;
43
48
import org .springframework .transaction .support .TransactionSynchronizationManager ;
54
59
* @author Jens Schauder
55
60
* @author Greg Turnquist
56
61
* @author Yuriy Tsarkov
57
- * @author Ariel Morelli Andres (Atlassian US, Inc.)
62
+ * @author Ariel Morelli Andres
58
63
*/
59
64
public enum PersistenceProvider implements QueryExtractor , ProxyIdAccessor , QueryComment {
60
65
61
66
/**
62
67
* Hibernate persistence provider.
63
- * <p>
64
- * Since Hibernate 4.3 the location of the HibernateEntityManager moved to the org.hibernate.jpa package. In order to
65
- * support both locations we interpret both classnames as a Hibernate {@code PersistenceProvider}.
66
- *
67
- * @see <a href="https://github.com/spring-projects/spring-data-jpa/issues/846">DATAJPA-444</a>
68
68
*/
69
- HIBERNATE (//
70
- Collections .singletonList (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
71
- Collections .singletonList (HIBERNATE_ENTITY_MANAGER_INTERFACE ), //
72
- Collections .singletonList (HIBERNATE_JPA_METAMODEL_TYPE )) {
69
+ HIBERNATE (List .of (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
70
+ List .of (HIBERNATE_JPA_METAMODEL_TYPE )) {
73
71
74
72
@ Override
75
73
public String extractQueryString (Query query ) {
@@ -117,9 +115,7 @@ public String getCommentHintKey() {
117
115
/**
118
116
* EclipseLink persistence provider.
119
117
*/
120
- ECLIPSELINK (List .of (ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 , ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 ),
121
- Collections .singleton (ECLIPSELINK_ENTITY_MANAGER_INTERFACE ),
122
- Collections .singleton (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
118
+ ECLIPSELINK (List .of (ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE ), List .of (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
123
119
124
120
@ Override
125
121
public String extractQueryString (Query query ) {
@@ -157,8 +153,7 @@ public String getCommentHintValue(String comment) {
157
153
/**
158
154
* Unknown special provider. Use standard JPA.
159
155
*/
160
- GENERIC_JPA (Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ),
161
- Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ), Collections .emptySet ()) {
156
+ GENERIC_JPA (List .of (GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE ), Collections .emptySet ()) {
162
157
163
158
@ Nullable
164
159
@ Override
@@ -205,8 +200,7 @@ public String getCommentHintKey() {
205
200
private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
206
201
207
202
private static final ConcurrentReferenceHashMap <Class <?>, PersistenceProvider > CACHE = new ConcurrentReferenceHashMap <>();
208
- private final Iterable <String > entityManagerFactoryClassNames ;
209
- private final Iterable <String > entityManagerClassNames ;
203
+ final Iterable <String > entityManagerFactoryClassNames ;
210
204
private final Iterable <String > metamodelClassNames ;
211
205
212
206
private final boolean present ;
@@ -216,37 +210,15 @@ public String getCommentHintKey() {
216
210
*
217
211
* @param entityManagerFactoryClassNames the names of the provider specific
218
212
* {@link jakarta.persistence.EntityManagerFactory} implementations. Must not be {@literal null} or empty.
219
- * @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
220
- * be {@literal null} or empty.
221
- * @param metamodelClassNames must not be {@literal null}.
213
+ * @param metamodelClassNames the names of the provider specific {@link Metamodel} implementations. Must not be
214
+ * {@literal null} or empty.
222
215
*/
223
- PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
224
- Iterable <String > metamodelClassNames ) {
216
+ PersistenceProvider (Collection <String > entityManagerFactoryClassNames , Collection <String > metamodelClassNames ) {
225
217
226
218
this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
227
- this .entityManagerClassNames = entityManagerClassNames ;
228
219
this .metamodelClassNames = metamodelClassNames ;
229
-
230
- boolean present = false ;
231
- for (String emfClassName : entityManagerFactoryClassNames ) {
232
-
233
- if (ClassUtils .isPresent (emfClassName , PersistenceProvider .class .getClassLoader ())) {
234
- present = true ;
235
- break ;
236
- }
237
- }
238
-
239
- if (!present ) {
240
- for (String entityManagerClassName : entityManagerClassNames ) {
241
-
242
- if (ClassUtils .isPresent (entityManagerClassName , PersistenceProvider .class .getClassLoader ())) {
243
- present = true ;
244
- break ;
245
- }
246
- }
247
- }
248
-
249
- this .present = present ;
220
+ this .present = Stream .concat (entityManagerFactoryClassNames .stream (), metamodelClassNames .stream ())
221
+ .anyMatch (it -> ClassUtils .isPresent (it , PersistenceProvider .class .getClassLoader ()));
250
222
}
251
223
252
224
/**
@@ -262,32 +234,23 @@ private static PersistenceProvider cacheAndReturn(Class<?> type, PersistenceProv
262
234
}
263
235
264
236
/**
265
- * Determines the {@link PersistenceProvider} from the given {@link EntityManager}. If no special one can be
237
+ * Determines the {@link PersistenceProvider} from the given {@link EntityManager} by introspecting
238
+ * {@link EntityManagerFactory} via {@link EntityManager#getEntityManagerFactory()}. If no special one can be
266
239
* determined {@link #GENERIC_JPA} will be returned.
240
+ * <p>
241
+ * This method avoids {@link EntityManager} initialization when using
242
+ * {@link org.springframework.orm.jpa.SharedEntityManagerCreator} by accessing
243
+ * {@link EntityManager#getEntityManagerFactory()}.
267
244
*
268
245
* @param em must not be {@literal null}.
269
246
* @return will never be {@literal null}.
247
+ * @see org.springframework.orm.jpa.SharedEntityManagerCreator
270
248
*/
271
249
public static PersistenceProvider fromEntityManager (EntityManager em ) {
272
250
273
251
Assert .notNull (em , "EntityManager must not be null" );
274
252
275
- Class <?> entityManagerType = em .getDelegate ().getClass ();
276
- PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
277
-
278
- if (cachedProvider != null ) {
279
- return cachedProvider ;
280
- }
281
-
282
- for (PersistenceProvider provider : ALL ) {
283
- for (String entityManagerClassName : provider .entityManagerClassNames ) {
284
- if (isEntityManagerOfType (em , entityManagerClassName )) {
285
- return cacheAndReturn (entityManagerType , provider );
286
- }
287
- }
288
- }
289
-
290
- return cacheAndReturn (entityManagerType , GENERIC_JPA );
253
+ return fromEntityManagerFactory (em .getEntityManagerFactory ());
291
254
}
292
255
293
256
/**
@@ -296,12 +259,24 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
296
259
*
297
260
* @param emf must not be {@literal null}.
298
261
* @return will never be {@literal null}.
262
+ * @since 3.5.1
299
263
*/
300
264
public static PersistenceProvider fromEntityManagerFactory (EntityManagerFactory emf ) {
301
265
302
266
Assert .notNull (emf , "EntityManagerFactory must not be null" );
303
267
304
- Class <?> entityManagerType = emf .getPersistenceUnitUtil ().getClass ();
268
+ EntityManagerFactory unwrapped = emf ;
269
+
270
+ while (Proxy .isProxyClass (unwrapped .getClass ()) || AopUtils .isAopProxy (unwrapped )) {
271
+
272
+ if (Proxy .isProxyClass (unwrapped .getClass ())) {
273
+ unwrapped = unwrapped .unwrap (null );
274
+ } else if (AopUtils .isAopProxy (unwrapped )) {
275
+ unwrapped = (EntityManagerFactory ) AopProxyUtils .getSingletonTarget (unwrapped );
276
+ }
277
+ }
278
+
279
+ Class <?> entityManagerType = unwrapped .getClass ();
305
280
PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
306
281
307
282
if (cachedProvider != null ) {
@@ -310,8 +285,7 @@ public static PersistenceProvider fromEntityManagerFactory(EntityManagerFactory
310
285
311
286
for (PersistenceProvider provider : ALL ) {
312
287
for (String emfClassName : provider .entityManagerFactoryClassNames ) {
313
- if (isOfType (emf .getPersistenceUnitUtil (), emfClassName ,
314
- emf .getPersistenceUnitUtil ().getClass ().getClassLoader ())) {
288
+ if (isOfType (unwrapped , emfClassName , unwrapped .getClass ().getClassLoader ())) {
315
289
return cacheAndReturn (entityManagerType , provider );
316
290
}
317
291
}
@@ -408,16 +382,14 @@ interface Constants {
408
382
String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
409
383
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager" ;
410
384
411
- String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate" ;
412
- String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl" ;
385
+ String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManagerFactory" ;
413
386
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
387
+ String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
414
388
415
389
// needed as Spring only exposes that interface via the EM proxy
416
- String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.jpa.internal.PersistenceUnitUtilImpl" ;
417
- String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.engine.spi.SessionImplementor" ;
418
-
390
+ String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.SessionFactory" ;
391
+ String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.Session" ;
419
392
String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
420
- String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
421
393
422
394
}
423
395
0 commit comments