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 ;
@@ -65,14 +66,20 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
65
66
* @see <a href="https://github.com/spring-projects/spring-data-jpa/issues/846">DATAJPA-444</a>
66
67
*/
67
68
HIBERNATE (//
69
+ Collections .singletonList (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
68
70
Collections .singletonList (HIBERNATE_ENTITY_MANAGER_INTERFACE ), //
69
71
Collections .singletonList (HIBERNATE_JPA_METAMODEL_TYPE )) {
70
72
71
73
@ Override
72
- public @ Nullable String extractQueryString (Query query ) {
74
+ public @ Nullable String extractQueryString (Object query ) {
73
75
return HibernateUtils .getHibernateQuery (query );
74
76
}
75
77
78
+ @ Override
79
+ public boolean isNativeQuery (Object query ) {
80
+ return HibernateUtils .isNativeQuery (query );
81
+ }
82
+
76
83
/**
77
84
* Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with
78
85
* compound keys.
@@ -115,14 +122,20 @@ public String getCommentHintKey() {
115
122
/**
116
123
* EclipseLink persistence provider.
117
124
*/
118
- ECLIPSELINK (Collections .singleton (ECLIPSELINK_ENTITY_MANAGER_INTERFACE ),
125
+ ECLIPSELINK (List .of (ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 , ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 ),
126
+ Collections .singleton (ECLIPSELINK_ENTITY_MANAGER_INTERFACE ),
119
127
Collections .singleton (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
120
128
121
129
@ Override
122
- public String extractQueryString (Query query ) {
130
+ public String extractQueryString (Object query ) {
123
131
return ((JpaQuery <?>) query ).getDatabaseQuery ().getJPQLString ();
124
132
}
125
133
134
+ @ Override
135
+ public boolean isNativeQuery (Object query ) {
136
+ return false ;
137
+ }
138
+
126
139
@ Override
127
140
public boolean shouldUseAccessorFor (Object entity ) {
128
141
return false ;
@@ -152,13 +165,19 @@ public String getCommentHintValue(String comment) {
152
165
/**
153
166
* Unknown special provider. Use standard JPA.
154
167
*/
155
- GENERIC_JPA (Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ), Collections .emptySet ()) {
168
+ GENERIC_JPA (Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ),
169
+ Collections .singleton (GENERIC_JPA_ENTITY_MANAGER_INTERFACE ), Collections .emptySet ()) {
156
170
157
171
@ Override
158
- public @ Nullable String extractQueryString (Query query ) {
172
+ public @ Nullable String extractQueryString (Object query ) {
159
173
return null ;
160
174
}
161
175
176
+ @ Override
177
+ public boolean isNativeQuery (Object query ) {
178
+ return false ;
179
+ }
180
+
162
181
@ Override
163
182
public boolean canExtractQuery () {
164
183
return false ;
@@ -196,6 +215,7 @@ public boolean shouldUseAccessorFor(Object entity) {
196
215
private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
197
216
198
217
private static final ConcurrentReferenceHashMap <Class <?>, PersistenceProvider > CACHE = new ConcurrentReferenceHashMap <>();
218
+ private final Iterable <String > entityManagerFactoryClassNames ;
199
219
private final Iterable <String > entityManagerClassNames ;
200
220
private final Iterable <String > metamodelClassNames ;
201
221
@@ -204,24 +224,38 @@ public boolean shouldUseAccessorFor(Object entity) {
204
224
/**
205
225
* Creates a new {@link PersistenceProvider}.
206
226
*
227
+ * @param entityManagerFactoryClassNames the names of the provider specific
228
+ * {@link jakarta.persistence.EntityManagerFactory} implementations. Must not be {@literal null} or empty.
207
229
* @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
208
230
* be {@literal null} or empty.
209
231
* @param metamodelClassNames must not be {@literal null}.
210
232
*/
211
- PersistenceProvider (Iterable <String > entityManagerClassNames , Iterable <String > metamodelClassNames ) {
233
+ PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
234
+ Iterable <String > metamodelClassNames ) {
212
235
236
+ this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
213
237
this .entityManagerClassNames = entityManagerClassNames ;
214
238
this .metamodelClassNames = metamodelClassNames ;
215
239
216
240
boolean present = false ;
217
- for (String entityManagerClassName : entityManagerClassNames ) {
241
+ for (String emfClassName : entityManagerFactoryClassNames ) {
218
242
219
- if (ClassUtils .isPresent (entityManagerClassName , PersistenceProvider .class .getClassLoader ())) {
243
+ if (ClassUtils .isPresent (emfClassName , PersistenceProvider .class .getClassLoader ())) {
220
244
present = true ;
221
245
break ;
222
246
}
223
247
}
224
248
249
+ if (!present ) {
250
+ for (String entityManagerClassName : entityManagerClassNames ) {
251
+
252
+ if (ClassUtils .isPresent (entityManagerClassName , PersistenceProvider .class .getClassLoader ())) {
253
+ present = true ;
254
+ break ;
255
+ }
256
+ }
257
+ }
258
+
225
259
this .present = present ;
226
260
}
227
261
@@ -266,6 +300,36 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
266
300
return cacheAndReturn (entityManagerType , GENERIC_JPA );
267
301
}
268
302
303
+ /**
304
+ * Determines the {@link PersistenceProvider} from the given {@link EntityManager}. If no special one can be
305
+ * determined {@link #GENERIC_JPA} will be returned.
306
+ *
307
+ * @param emf must not be {@literal null}.
308
+ * @return will never be {@literal null}.
309
+ */
310
+ public static PersistenceProvider fromEntityManagerFactory (EntityManagerFactory emf ) {
311
+
312
+ Assert .notNull (emf , "EntityManager must not be null" );
313
+
314
+ Class <?> entityManagerType = emf .getPersistenceUnitUtil ().getClass ();
315
+ PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
316
+
317
+ if (cachedProvider != null ) {
318
+ return cachedProvider ;
319
+ }
320
+
321
+ for (PersistenceProvider provider : ALL ) {
322
+ for (String emfClassName : provider .entityManagerFactoryClassNames ) {
323
+ if (isOfType (emf .getPersistenceUnitUtil (), emfClassName ,
324
+ emf .getPersistenceUnitUtil ().getClass ().getClassLoader ())) {
325
+ return cacheAndReturn (entityManagerType , provider );
326
+ }
327
+ }
328
+ }
329
+
330
+ return cacheAndReturn (entityManagerType , GENERIC_JPA );
331
+ }
332
+
269
333
/**
270
334
* Determines the {@link PersistenceProvider} from the given {@link Metamodel}. If no special one can be determined
271
335
* {@link #GENERIC_JPA} will be returned.
@@ -350,9 +414,15 @@ public boolean isPresent() {
350
414
*/
351
415
interface Constants {
352
416
417
+ String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
353
418
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager" ;
419
+
420
+ String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate" ;
421
+ String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl" ;
354
422
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
423
+
355
424
// needed as Spring only exposes that interface via the EM proxy
425
+ String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.jpa.internal.PersistenceUnitUtilImpl" ;
356
426
String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.engine.spi.SessionImplementor" ;
357
427
358
428
String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
0 commit comments