From ca709a09e306411b338cbaf55e77bf40dee94c7e Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Tue, 31 Jul 2018 08:09:16 +0200 Subject: [PATCH] DATAJPA-1379 - Fixed detection of PersistenceProvider when EntityManager is a proxy. We now use the delegate to test the applicability of the PersistenceProvider not just for determining the and the key cash. This fixes the issue because the underlying issue was that the generic PersistenceProvider was used. Which return false for `canExtractQuery` which prevented the constructor call in the query to be detected. Original pull request: #287. --- .../data/jpa/provider/JpaClassUtils.java | 6 +++++- .../jpa/provider/PersistenceProvider.java | 3 ++- .../PersistenceProviderUnitTests.java | 19 ++++++++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/provider/JpaClassUtils.java b/src/main/java/org/springframework/data/jpa/provider/JpaClassUtils.java index 27e72edaf..44bac78c6 100644 --- a/src/main/java/org/springframework/data/jpa/provider/JpaClassUtils.java +++ b/src/main/java/org/springframework/data/jpa/provider/JpaClassUtils.java @@ -43,7 +43,11 @@ abstract class JpaClassUtils { * @return */ public static boolean isEntityManagerOfType(EntityManager em, String type) { - return isOfType(em, type, em.getDelegate().getClass().getClassLoader()); + Object delegate = em.getDelegate(); + if (delegate instanceof EntityManager) { + em = (EntityManager) delegate; + } + return isOfType(em, type, delegate.getClass().getClassLoader()); } public static boolean isMetamodelOfType(Metamodel metamodel, String type) { diff --git a/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java b/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java index b006c05cc..b2e9dec20 100644 --- a/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java +++ b/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java @@ -44,6 +44,7 @@ import org.springframework.util.ConcurrentReferenceHashMap; * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Jens Schauder */ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor { @@ -224,7 +225,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor { String OPENJPA_JPA_METAMODEL_TYPE = "org.apache.openjpa.persistence.meta.MetamodelImpl"; } - private static ConcurrentReferenceHashMap, PersistenceProvider> CACHE = new ConcurrentReferenceHashMap, PersistenceProvider>(); + static ConcurrentReferenceHashMap, PersistenceProvider> CACHE = new ConcurrentReferenceHashMap, PersistenceProvider>(); private final Iterable entityManagerClassNames; private final Iterable metamodelClassNames; diff --git a/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java b/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java index c8512621c..e63ffc9bd 100644 --- a/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java @@ -40,6 +40,7 @@ import org.springframework.util.ClassUtils; * * @author Thomas Darimont * @author Oliver Gierke + * @author Jens Schauder */ public class PersistenceProviderUnitTests { @@ -47,6 +48,9 @@ public class PersistenceProviderUnitTests { @Before public void setup() { + + PersistenceProvider.CACHE.clear(); + this.shadowingClassLoader = new ShadowingClassLoader(getClass().getClassLoader()); } @@ -80,12 +84,25 @@ public class PersistenceProviderUnitTests { assertThat(fromEntityManager(em), is(HIBERNATE)); } + @Test // DATAJPA-1379 + public void detectsProviderFromProxiedEntityManager() throws Exception { + + shadowingClassLoader.excludePackage("org.eclipse.persistence.jpa"); + + EntityManager em = mockProviderSpecificEntityManagerInterface(ECLIPSELINK_ENTITY_MANAGER_INTERFACE); + + EntityManager emProxy = Mockito.mock(EntityManager.class); + Mockito.when(emProxy.getDelegate()).thenReturn(em); + + assertThat(fromEntityManager(emProxy), is(ECLIPSELINK)); + } + private EntityManager mockProviderSpecificEntityManagerInterface(String interfaceName) throws ClassNotFoundException { Class providerSpecificEntityManagerInterface = InterfaceGenerator.generate(interfaceName, shadowingClassLoader, EntityManager.class); - EntityManager em = EntityManager.class.cast(Mockito.mock(providerSpecificEntityManagerInterface)); + EntityManager em = (EntityManager) Mockito.mock(providerSpecificEntityManagerInterface); Mockito.when(em.getDelegate()).thenReturn(em); // delegate is used to determine the classloader of the provider // specific interface, therefore we return the proxied // EntityManager.