1919import static org .springframework .data .jpa .provider .PersistenceProvider .Constants .*;
2020
2121import jakarta .persistence .EntityManager ;
22+ import jakarta .persistence .EntityManagerFactory ;
2223import jakarta .persistence .Query ;
2324import jakarta .persistence .metamodel .IdentifiableType ;
2425import jakarta .persistence .metamodel .Metamodel ;
3637import org .hibernate .ScrollMode ;
3738import org .hibernate .ScrollableResults ;
3839import org .hibernate .proxy .HibernateProxy ;
40+
3941import org .springframework .data .util .CloseableIterator ;
4042import org .springframework .lang .Nullable ;
4143import org .springframework .transaction .support .TransactionSynchronizationManager ;
5254 * @author Jens Schauder
5355 * @author Greg Turnquist
5456 * @author Yuriy Tsarkov
57+ * @author Ariel Morelli Andres (Atlassian US, Inc.)
5558 */
5659public enum PersistenceProvider implements QueryExtractor , ProxyIdAccessor , QueryComment {
5760
@@ -64,14 +67,14 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
6467 * @see <a href="https://github.com/spring-projects/spring-data-jpa/issues/846">DATAJPA-444</a>
6568 */
6669 HIBERNATE (//
70+ Collections .singletonList (HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE ), //
6771 Collections .singletonList (HIBERNATE_ENTITY_MANAGER_INTERFACE ), //
6872 Collections .singletonList (HIBERNATE_JPA_METAMODEL_TYPE )) {
6973
7074 @ Override
7175 public String extractQueryString (Query query ) {
7276 return HibernateUtils .getHibernateQuery (query );
7377 }
74-
7578 /**
7679 * Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with
7780 * compound keys.
@@ -114,7 +117,8 @@ public String getCommentHintKey() {
114117 /**
115118 * EclipseLink persistence provider.
116119 */
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 ),
118122 Collections .singleton (ECLIPSELINK_JPA_METAMODEL_TYPE )) {
119123
120124 @ Override
@@ -147,12 +151,14 @@ public String getCommentHintKey() {
147151 public String getCommentHintValue (String comment ) {
148152 return "/* " + comment + " */" ;
149153 }
154+
150155 },
151156
152157 /**
153158 * Unknown special provider. Use standard JPA.
154159 */
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 ()) {
156162
157163 @ Nullable
158164 @ Override
@@ -199,6 +205,7 @@ public String getCommentHintKey() {
199205 private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
200206
201207 private static final ConcurrentReferenceHashMap <Class <?>, PersistenceProvider > CACHE = new ConcurrentReferenceHashMap <>();
208+ private final Iterable <String > entityManagerFactoryClassNames ;
202209 private final Iterable <String > entityManagerClassNames ;
203210 private final Iterable <String > metamodelClassNames ;
204211
@@ -207,24 +214,38 @@ public String getCommentHintKey() {
207214 /**
208215 * Creates a new {@link PersistenceProvider}.
209216 *
217+ * @param entityManagerFactoryClassNames the names of the provider specific
218+ * {@link jakarta.persistence.EntityManagerFactory} implementations. Must not be {@literal null} or empty.
210219 * @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
211220 * be {@literal null} or empty.
212221 * @param metamodelClassNames must not be {@literal null}.
213222 */
214- PersistenceProvider (Iterable <String > entityManagerClassNames , Iterable <String > metamodelClassNames ) {
223+ PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
224+ Iterable <String > metamodelClassNames ) {
215225
226+ this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
216227 this .entityManagerClassNames = entityManagerClassNames ;
217228 this .metamodelClassNames = metamodelClassNames ;
218229
219230 boolean present = false ;
220- for (String entityManagerClassName : entityManagerClassNames ) {
231+ for (String emfClassName : entityManagerFactoryClassNames ) {
221232
222- if (ClassUtils .isPresent (entityManagerClassName , PersistenceProvider .class .getClassLoader ())) {
233+ if (ClassUtils .isPresent (emfClassName , PersistenceProvider .class .getClassLoader ())) {
223234 present = true ;
224235 break ;
225236 }
226237 }
227238
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+
228249 this .present = present ;
229250 }
230251
@@ -269,6 +290,36 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
269290 return cacheAndReturn (entityManagerType , GENERIC_JPA );
270291 }
271292
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+
272323 /**
273324 * Determines the {@link PersistenceProvider} from the given {@link Metamodel}. If no special one can be determined
274325 * {@link #GENERIC_JPA} will be returned.
@@ -354,13 +405,20 @@ public boolean isPresent() {
354405 */
355406 interface Constants {
356407
408+ String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
357409 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" ;
358413 String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
414+
359415 // needed as Spring only exposes that interface via the EM proxy
416+ String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.jpa.internal.PersistenceUnitUtilImpl" ;
360417 String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.engine.spi.SessionImplementor" ;
361418
362419 String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
363420 String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
421+
364422 }
365423
366424 public CloseableIterator <Object > executeQueryWithResultStream (Query jpaQuery ) {
@@ -465,5 +523,7 @@ public void close() {
465523 scrollableCursor .close ();
466524 }
467525 }
526+
468527 }
528+
469529}
0 commit comments