2525import jakarta .persistence .metamodel .Metamodel ;
2626import jakarta .persistence .metamodel .SingularAttribute ;
2727
28+ import java .lang .reflect .Proxy ;
2829import java .util .Collection ;
2930import java .util .Collections ;
3031import java .util .List ;
3132import java .util .NoSuchElementException ;
3233import java .util .Set ;
34+ import java .util .function .LongSupplier ;
35+ import java .util .stream .Stream ;
3336
3437import org .eclipse .persistence .config .QueryHints ;
3538import org .eclipse .persistence .jpa .JpaQuery ;
3841import org .hibernate .ScrollableResults ;
3942import org .hibernate .proxy .HibernateProxy ;
4043
44+ import org .springframework .aop .framework .AopProxyUtils ;
45+ import org .springframework .aop .support .AopUtils ;
4146import org .springframework .data .util .CloseableIterator ;
4247import org .springframework .lang .Nullable ;
4348import org .springframework .transaction .support .TransactionSynchronizationManager ;
5459 * @author Jens Schauder
5560 * @author Greg Turnquist
5661 * @author Yuriy Tsarkov
57- * @author Ariel Morelli Andres (Atlassian US, Inc.)
62+ * @author Ariel Morelli Andres
5863 */
5964public enum PersistenceProvider implements QueryExtractor , ProxyIdAccessor , QueryComment {
6065
6166 /**
6267 * 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>
6868 */
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 )) {
7371
7472 @ Override
7573 public String extractQueryString (Query query ) {
@@ -117,9 +115,7 @@ public String getCommentHintKey() {
117115 /**
118116 * EclipseLink persistence provider.
119117 */
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 )) {
123119
124120 @ Override
125121 public String extractQueryString (Query query ) {
@@ -157,8 +153,7 @@ public String getCommentHintValue(String comment) {
157153 /**
158154 * Unknown special provider. Use standard JPA.
159155 */
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 ()) {
162157
163158 @ Nullable
164159 @ Override
@@ -205,8 +200,7 @@ public String getCommentHintKey() {
205200 private static final Collection <PersistenceProvider > ALL = List .of (HIBERNATE , ECLIPSELINK , GENERIC_JPA );
206201
207202 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 ;
210204 private final Iterable <String > metamodelClassNames ;
211205
212206 private final boolean present ;
@@ -216,37 +210,15 @@ public String getCommentHintKey() {
216210 *
217211 * @param entityManagerFactoryClassNames the names of the provider specific
218212 * {@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.
222215 */
223- PersistenceProvider (Iterable <String > entityManagerFactoryClassNames , Iterable <String > entityManagerClassNames ,
224- Iterable <String > metamodelClassNames ) {
216+ PersistenceProvider (Collection <String > entityManagerFactoryClassNames , Collection <String > metamodelClassNames ) {
225217
226218 this .entityManagerFactoryClassNames = entityManagerFactoryClassNames ;
227- this .entityManagerClassNames = entityManagerClassNames ;
228219 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 ()));
250222 }
251223
252224 /**
@@ -262,32 +234,23 @@ private static PersistenceProvider cacheAndReturn(Class<?> type, PersistenceProv
262234 }
263235
264236 /**
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
266239 * 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()}.
267244 *
268245 * @param em must not be {@literal null}.
269246 * @return will never be {@literal null}.
247+ * @see org.springframework.orm.jpa.SharedEntityManagerCreator
270248 */
271249 public static PersistenceProvider fromEntityManager (EntityManager em ) {
272250
273251 Assert .notNull (em , "EntityManager must not be null" );
274252
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 ());
291254 }
292255
293256 /**
@@ -296,12 +259,24 @@ public static PersistenceProvider fromEntityManager(EntityManager em) {
296259 *
297260 * @param emf must not be {@literal null}.
298261 * @return will never be {@literal null}.
262+ * @since 3.5.1
299263 */
300264 public static PersistenceProvider fromEntityManagerFactory (EntityManagerFactory emf ) {
301265
302266 Assert .notNull (emf , "EntityManagerFactory must not be null" );
303267
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 ();
305280 PersistenceProvider cachedProvider = CACHE .get (entityManagerType );
306281
307282 if (cachedProvider != null ) {
@@ -310,8 +285,7 @@ public static PersistenceProvider fromEntityManagerFactory(EntityManagerFactory
310285
311286 for (PersistenceProvider provider : ALL ) {
312287 for (String emfClassName : provider .entityManagerFactoryClassNames ) {
313- if (isOfType (emf .getPersistenceUnitUtil (), emfClassName ,
314- emf .getPersistenceUnitUtil ().getClass ().getClassLoader ())) {
288+ if (isOfType (unwrapped , emfClassName , unwrapped .getClass ().getClassLoader ())) {
315289 return cacheAndReturn (entityManagerType , provider );
316290 }
317291 }
@@ -408,16 +382,14 @@ interface Constants {
408382 String GENERIC_JPA_ENTITY_MANAGER_FACTORY_INTERFACE = "jakarta.persistence.EntityManagerFactory" ;
409383 String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "jakarta.persistence.EntityManager" ;
410384
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" ;
413386 String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager" ;
387+ String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
414388
415389 // 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" ;
419392 String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.metamodel.model.domain.JpaMetamodel" ;
420- String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl" ;
421393
422394 }
423395
0 commit comments