diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java
index 2b5e0abbe..c8628861f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java
@@ -19,6 +19,7 @@ import static org.springframework.data.jpa.provider.JpaClassUtils.*;
import static org.springframework.data.jpa.provider.PersistenceProvider.Constants.*;
import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Query;
import jakarta.persistence.metamodel.IdentifiableType;
import jakarta.persistence.metamodel.Metamodel;
@@ -36,6 +37,7 @@ import org.eclipse.persistence.queries.ScrollableCursor;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.proxy.HibernateProxy;
+
import org.springframework.data.util.CloseableIterator;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -52,6 +54,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
* @author Jens Schauder
* @author Greg Turnquist
* @author Yuriy Tsarkov
+ * @author Ariel Morelli Andres (Atlassian US, Inc.)
*/
public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, QueryComment {
@@ -64,6 +67,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
* @see DATAJPA-444
*/
HIBERNATE(//
+ Collections.singletonList(HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE), //
Collections.singletonList(HIBERNATE_ENTITY_MANAGER_INTERFACE), //
Collections.singletonList(HIBERNATE_JPA_METAMODEL_TYPE)) {
@@ -71,7 +75,6 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
public String extractQueryString(Query query) {
return HibernateUtils.getHibernateQuery(query);
}
-
/**
* Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with
* compound keys.
@@ -114,7 +117,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
/**
* EclipseLink persistence provider.
*/
- ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE),
+ ECLIPSELINK(List.of(ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1, ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2),
+ Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE),
Collections.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
@Override
@@ -147,12 +151,14 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
public String getCommentHintValue(String comment) {
return "/* " + comment + " */";
}
+
},
/**
* Unknown special provider. Use standard JPA.
*/
- GENERIC_JPA(Collections.singleton(GENERIC_JPA_ENTITY_MANAGER_INTERFACE), Collections.emptySet()) {
+ GENERIC_JPA(Collections.singleton(GENERIC_JPA_ENTITY_MANAGER_INTERFACE),
+ Collections.singleton(GENERIC_JPA_ENTITY_MANAGER_INTERFACE), Collections.emptySet()) {
@Nullable
@Override
@@ -199,6 +205,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
private static final Collection ALL = List.of(HIBERNATE, ECLIPSELINK, GENERIC_JPA);
private static final ConcurrentReferenceHashMap, PersistenceProvider> CACHE = new ConcurrentReferenceHashMap<>();
+ private final Iterable entityManagerFactoryClassNames;
private final Iterable entityManagerClassNames;
private final Iterable metamodelClassNames;
@@ -207,24 +214,38 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
/**
* Creates a new {@link PersistenceProvider}.
*
+ * @param entityManagerFactoryClassNames the names of the provider specific
+ * {@link jakarta.persistence.EntityManagerFactory} implementations. Must not be {@literal null} or empty.
* @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
* be {@literal null} or empty.
* @param metamodelClassNames must not be {@literal null}.
*/
- PersistenceProvider(Iterable entityManagerClassNames, Iterable metamodelClassNames) {
+ PersistenceProvider(Iterable entityManagerFactoryClassNames, Iterable entityManagerClassNames,
+ Iterable metamodelClassNames) {
+ this.entityManagerFactoryClassNames = entityManagerFactoryClassNames;
this.entityManagerClassNames = entityManagerClassNames;
this.metamodelClassNames = metamodelClassNames;
boolean present = false;
- for (String entityManagerClassName : entityManagerClassNames) {
+ for (String emfClassName : entityManagerFactoryClassNames) {
- if (ClassUtils.isPresent(entityManagerClassName, PersistenceProvider.class.getClassLoader())) {
+ if (ClassUtils.isPresent(emfClassName, PersistenceProvider.class.getClassLoader())) {
present = true;
break;
}
}
+ if (!present) {
+ for (String entityManagerClassName : entityManagerClassNames) {
+
+ if (ClassUtils.isPresent(entityManagerClassName, PersistenceProvider.class.getClassLoader())) {
+ present = true;
+ break;
+ }
+ }
+ }
+
this.present = present;
}
@@ -269,6 +290,36 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
return cacheAndReturn(entityManagerType, GENERIC_JPA);
}
+ /**
+ * Determines the {@link PersistenceProvider} from the given {@link EntityManagerFactory}. If no special one can be
+ * determined {@link #GENERIC_JPA} will be returned.
+ *
+ * @param emf must not be {@literal null}.
+ * @return will never be {@literal null}.
+ */
+ public static PersistenceProvider fromEntityManagerFactory(EntityManagerFactory emf) {
+
+ Assert.notNull(emf, "EntityManagerFactory must not be null");
+
+ Class> entityManagerType = emf.getPersistenceUnitUtil().getClass();
+ PersistenceProvider cachedProvider = CACHE.get(entityManagerType);
+
+ if (cachedProvider != null) {
+ return cachedProvider;
+ }
+
+ for (PersistenceProvider provider : ALL) {
+ for (String emfClassName : provider.entityManagerFactoryClassNames) {
+ if (isOfType(emf.getPersistenceUnitUtil(), emfClassName,
+ emf.getPersistenceUnitUtil().getClass().getClassLoader())) {
+ return cacheAndReturn(entityManagerType, provider);
+ }
+ }
+ }
+
+ return cacheAndReturn(entityManagerType, GENERIC_JPA);
+ }
+
/**
* Determines the {@link PersistenceProvider} from the given {@link Metamodel}. If no special one can be determined
* {@link #GENERIC_JPA} will be returned.
@@ -354,13 +405,20 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
*/
interface Constants {
+ String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory";
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager";
+
+ String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE1 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate";
+ String ECLIPSELINK_ENTITY_MANAGER_FACTORY_INTERFACE2 = "org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl";
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager";
+
// needed as Spring only exposes that interface via the EM proxy
+ String HIBERNATE_ENTITY_MANAGER_FACTORY_INTERFACE = "org.hibernate.jpa.internal.PersistenceUnitUtilImpl";
String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.engine.spi.SessionImplementor";
String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel";
String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl";
+
}
public CloseableIterator