19
19
import static org .springframework .data .jpa .provider .PersistenceProvider .Constants .*;
20
20
21
21
import jakarta .persistence .EntityManager ;
22
+ import jakarta .persistence .EntityManagerFactory ;
22
23
import jakarta .persistence .Query ;
23
24
import jakarta .persistence .metamodel .IdentifiableType ;
24
25
import jakarta .persistence .metamodel .Metamodel ;
36
37
import org .hibernate .ScrollMode ;
37
38
import org .hibernate .ScrollableResults ;
38
39
import org .hibernate .proxy .HibernateProxy ;
40
+
39
41
import org .springframework .data .util .CloseableIterator ;
40
42
import org .springframework .lang .Nullable ;
41
43
import org .springframework .transaction .support .TransactionSynchronizationManager ;
52
54
* @author Jens Schauder
53
55
* @author Greg Turnquist
54
56
* @author Yuriy Tsarkov
57
+ * @author Ariel Morelli Andres (Atlassian US, Inc.)
55
58
*/
56
59
public enum PersistenceProvider implements QueryExtractor , ProxyIdAccessor , QueryComment {
57
60
@@ -64,14 +67,14 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
64
67
* @see <a href="https://github.com/spring-projects/spring-data-jpa/issues/846">DATAJPA-444</a>
65
68
*/
66
69
HIBERNATE (//
70
+ Collections .singletonList (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
67
71
Collections .singletonList (HIBERNATE_ENTITY_MANAGER_INTERFACE ), //
68
72
Collections .singletonList (HIBERNATE_JPA_METAMODEL_TYPE )) {
69
73
70
74
@ Override
71
75
public String extractQueryString (Query query ) {
72
76
return HibernateUtils .getHibernateQuery (query );
73
77
}
74
-
75
78
/**
76
79
* Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with
77
80
* compound keys.
@@ -114,7 +117,8 @@ public String getCommentHintKey() {
114
117
/**
115
118
* EclipseLink persistence provider.
116
119
*/
117
- ECLIPSELINK (Collections .singleton (ECLIPSELINK_ENTITY_MANAGER_INTERFACE ),
120
+ ECLIPSELINK (List .of (ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 , ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 ),
121
+ Collections .singleton (ECLIPSELINK_ENTITY_MANAGER_INTERFACE ),
118
122
Collections .singleton (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
119
123
120
124
@ Override
@@ -147,12 +151,14 @@ public String getCommentHintKey() {
147
151
public String getCommentHintValue (String comment ) {
148
152
return "/* " + comment + " */" ;
149
153
}
154
+
150
155
},
151
156
152
157
/**
153
158
* Unknown special provider. Use standard JPA.
154
159
*/
155
- GENERIC_JPA (Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ), Collections .emptySet ()) {
160
+ GENERIC_JPA (Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ),
161
+ Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ), Collections .emptySet ()) {
156
162
157
163
@ Nullable
158
164
@ Override
@@ -199,6 +205,7 @@ public String getCommentHintKey() {
199
205
private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
200
206
201
207
private static final ConcurrentReferenceHashMap <Class <?>, PersistenceProvider > CACHE = new ConcurrentReferenceHashMap <>();
208
+ private final Iterable <String > entityManagerFactoryClassNames ;
202
209
private final Iterable <String > entityManagerClassNames ;
203
210
private final Iterable <String > metamodelClassNames ;
204
211
@@ -207,24 +214,38 @@ public String getCommentHintKey() {
207
214
/**
208
215
* Creates a new {@link PersistenceProvider}.
209
216
*
217
+ * @param entityManagerFactoryClassNames the names of the provider specific
218
+ * {@link jakarta.persistence.EntityManagerFactory} implementations. Must not be {@literal null} or empty.
210
219
* @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
211
220
* be {@literal null} or empty.
212
221
* @param metamodelClassNames must not be {@literal null}.
213
222
*/
214
- PersistenceProvider (Iterable <String > entityManagerClassNames , Iterable <String > metamodelClassNames ) {
223
+ PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
224
+ Iterable <String > metamodelClassNames ) {
215
225
226
+ this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
216
227
this .entityManagerClassNames = entityManagerClassNames ;
217
228
this .metamodelClassNames = metamodelClassNames ;
218
229
219
230
boolean present = false ;
220
- for (String entityManagerClassName : entityManagerClassNames ) {
231
+ for (String emfClassName : entityManagerFactoryClassNames ) {
221
232
222
- if (ClassUtils .isPresent (entityManagerClassName , PersistenceProvider .class .getClassLoader ())) {
233
+ if (ClassUtils .isPresent (emfClassName , PersistenceProvider .class .getClassLoader ())) {
223
234
present = true ;
224
235
break ;
225
236
}
226
237
}
227
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
+
228
249
this .present = present ;
229
250
}
230
251
@@ -269,6 +290,36 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
269
290
return cacheAndReturn (entityManagerType , GENERIC_JPA );
270
291
}
271
292
293
+ /**
294
+ * Determines the {@link PersistenceProvider} from the given {@link EntityManagerFactory}. If no special one can be
295
+ * determined {@link #GENERIC_JPA} will be returned.
296
+ *
297
+ * @param emf must not be {@literal null}.
298
+ * @return will never be {@literal null}.
299
+ */
300
+ public static PersistenceProvider fromEntityManagerFactory (EntityManagerFactory emf ) {
301
+
302
+ Assert .notNull (emf , "EntityManagerFactory must not be null" );
303
+
304
+ Class <?> entityManagerType = emf .getPersistenceUnitUtil ().getClass ();
305
+ PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
306
+
307
+ if (cachedProvider != null ) {
308
+ return cachedProvider ;
309
+ }
310
+
311
+ for (PersistenceProvider provider : ALL ) {
312
+ for (String emfClassName : provider .entityManagerFactoryClassNames ) {
313
+ if (isOfType (emf .getPersistenceUnitUtil (), emfClassName ,
314
+ emf .getPersistenceUnitUtil ().getClass ().getClassLoader ())) {
315
+ return cacheAndReturn (entityManagerType , provider );
316
+ }
317
+ }
318
+ }
319
+
320
+ return cacheAndReturn (entityManagerType , GENERIC_JPA );
321
+ }
322
+
272
323
/**
273
324
* Determines the {@link PersistenceProvider} from the given {@link Metamodel}. If no special one can be determined
274
325
* {@link #GENERIC_JPA} will be returned.
@@ -354,13 +405,20 @@ public boolean isPresent() {
354
405
*/
355
406
interface Constants {
356
407
408
+ String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
357
409
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager" ;
410
+
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" ;
358
413
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
414
+
359
415
// needed as Spring only exposes that interface via the EM proxy
416
+ String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.jpa.internal.PersistenceUnitUtilImpl" ;
360
417
String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.engine.spi.SessionImplementor" ;
361
418
362
419
String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
363
420
String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
421
+
364
422
}
365
423
366
424
public CloseableIterator <Object > executeQueryWithResultStream (Query jpaQuery ) {
@@ -465,5 +523,7 @@ public void close() {
465
523
scrollableCursor .close ();
466
524
}
467
525
}
526
+
468
527
}
528
+
469
529
}
0 commit comments