From 196655a9976bd2e0de373f4eab4514743b1f6fc0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 3 Jun 2016 19:33:07 +0200 Subject: [PATCH] DATAJPA-911 - Assert compatibility with Hibernate 5.2. We now use a completely reflective lookup of the Hibernate query string as well as for the Hibernate specific PersistenceProvider lookup in tests. Added build profile for Hibernate 5.2 but it's currently not working due to Hibernate complaining about an invalid identifier mapping on CustomAbstractPersistable which is overriding the parent types property on accessor working fine on 5.1. The build profile for 5.1 is still broken due to the fixed but yet unreleased HHH-10514 [0] and the not yet fixed HHH-10515 [1] (apparently fixed but still open and unreleased) which has been broken since 5.0.8. [0] https://hibernate.atlassian.net/browse/HHH-10514 [1] https://hibernate.atlassian.net/browse/HHH-10515 --- pom.xml | 10 ++- .../data/jpa/provider/HibernateUtils.java | 66 +++++++++++++++++++ .../jpa/provider/PersistenceProvider.java | 3 +- .../infrastructure/HibernateTestUtils.java | 60 +++++++++++++++++ .../CrudMethodMetadataUnitTests.java | 5 +- .../PartTreeJpaQueryIntegrationTests.java | 9 ++- .../query/QueryUtilsIntegrationTests.java | 10 +-- .../DefaultJpaContextIntegrationTests.java | 6 +- 8 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/springframework/data/jpa/provider/HibernateUtils.java create mode 100644 src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java diff --git a/pom.xml b/pom.xml index d1bcf0df2..f890f989e 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ 2.6.2 3.6.10.Final + hibernate-entitymanager 1.8.0.10 2.0.0 2.3.0 @@ -88,6 +89,13 @@ + + hibernate-52 + + 5.2.0.Final + hibernate-core + + eclipselink-next @@ -215,7 +223,7 @@ org.hibernate - hibernate-entitymanager + ${hibernate.artifact} ${hibernate} true diff --git a/src/main/java/org/springframework/data/jpa/provider/HibernateUtils.java b/src/main/java/org/springframework/data/jpa/provider/HibernateUtils.java new file mode 100644 index 000000000..84ce421b7 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/provider/HibernateUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jpa.provider; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.hibernate.Query; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; + +/** + * Utility functions to work with Hibernate. Mostly using reflection to make sure common functionality can be executed + * against all the Hibernate version we support. + * + * @since 1.10.2 + * @soundtrack Benny Greb - Soulfood (Live, https://www.youtube.com/watch?v=9_ErMa_CtSw) + */ +@SuppressWarnings({ "deprecation", "rawtypes" }) +public abstract class HibernateUtils { + + private static final List TYPES = Arrays.asList("org.hibernate.jpa.HibernateQuery", + "org.hibernate.ejb.HibernateQuery"); + private static final Method GET_HIBERNATE_QUERY; + + private HibernateUtils() {} + + static { + + Class type = null; + Method method = null; + + for (String typeName : TYPES) { + try { + type = ClassUtils.forName(typeName, HibernateUtils.class.getClassLoader()); + method = type.getMethod("getHibernateQuery"); + } catch (Exception o_O) {} + } + + GET_HIBERNATE_QUERY = method; + } + + /** + * Return the query string of the underlying native Hibernate query. + * + * @param query + * @return + */ + public static String getHibernateQuery(Object query) { + return ((Query) ReflectionUtils.invokeMethod(GET_HIBERNATE_QUERY, query)).getQueryString(); + } +} 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 777011cb4..1c9eb844b 100644 --- a/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java +++ b/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java @@ -39,7 +39,6 @@ import org.eclipse.persistence.jpa.JpaQuery; import org.eclipse.persistence.queries.ScrollableCursor; import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; -import org.hibernate.ejb.HibernateQuery; import org.hibernate.proxy.HibernateProxy; import org.springframework.data.util.CloseableIterator; import org.springframework.transaction.support.TransactionSynchronizationManager; @@ -67,7 +66,7 @@ public enum PersistenceProvider implements QueryExtractor,ProxyIdAccessor { Arrays.asList(HIBERNATE43_JPA_METAMODEL_TYPE, HIBERNATE_JPA_METAMODEL_TYPE)) { public String extractQueryString(Query query) { - return ((HibernateQuery) query).getHibernateQuery().getQueryString(); + return HibernateUtils.getHibernateQuery(query); } /** diff --git a/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java b/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java new file mode 100644 index 000000000..34329c932 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jpa.infrastructure; + +import java.util.Arrays; +import java.util.List; + +import javax.persistence.spi.PersistenceProvider; + +import org.springframework.util.ClassUtils; + +/** + * Testing utilities for Hibernate. + * + * @author Oliver Gierke + * @soundtrack Ron Spielman - Africa's Napoleon (Swimming In The Dark) + * @since 1.10.2 + */ +public class HibernateTestUtils { + + private static final List PROVIDER_TYPES = Arrays.asList("org.hibernate.jpa.HibernatePersistenceProvider", + "org.hibernate.ejb.HibernatePersistence"); + + /** + * Returns the Hibernate {@link PersistenceProvider}. + * + * @return + */ + public static PersistenceProvider getPersistenceProvider() { + + ClassLoader classLoader = HibernateTestUtils.class.getClassLoader(); + + for (String provider : PROVIDER_TYPES) { + + if (ClassUtils.isPresent(provider, classLoader)) { + + try { + return (PersistenceProvider) ClassUtils.forName(provider, classLoader).newInstance(); + } catch (Exception o_O) { + throw new RuntimeException(o_O); + } + } + } + + throw new IllegalStateException("Could not obtain Hibernate PersistenceProvider!"); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java index 3f3a20553..d705e5650 100644 --- a/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,6 @@ import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; -import org.hibernate.ejb.HibernateEntityManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -117,7 +116,7 @@ public class CrudMethodMetadataUnitTests { @Test public void appliesLockModeAndQueryHintsToQuerydslQuery() { - when(em.getDelegate()).thenReturn(mock(HibernateEntityManager.class)); + when(em.getDelegate()).thenReturn(mock(EntityManager.class)); when(em.createQuery(anyString())).thenReturn(query); repository.findOne(QRole.role.name.eq("role")); diff --git a/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java index 8ac508283..b2d8d8a1b 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java @@ -33,7 +33,6 @@ import javax.persistence.Query; import javax.persistence.TemporalType; import org.hibernate.Version; -import org.hibernate.ejb.HibernateQuery; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -42,6 +41,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.sample.User; +import org.springframework.data.jpa.provider.HibernateUtils; import org.springframework.data.jpa.provider.PersistenceProvider; import org.springframework.data.jpa.repository.Temporal; import org.springframework.data.repository.Repository; @@ -110,18 +110,17 @@ public class PartTreeJpaQueryIntegrationTests { Query query = jpaQuery.createQuery(new Object[] { "Matthews", new PageRequest(0, 1) }); - HibernateQuery hibernateQuery = getValue(query, PROPERTY); - assertThat(hibernateQuery.getHibernateQuery().getQueryString(), endsWith("firstname=:param0")); + assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY)), endsWith("firstname=:param0")); query = jpaQuery.createQuery(new Object[] { null, new PageRequest(0, 1) }); - hibernateQuery = getValue(query, PROPERTY); - assertThat(hibernateQuery.getHibernateQuery().getQueryString(), endsWith("firstname is null")); + assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY)), endsWith("firstname is null")); } private void testIgnoreCase(String methodName, Object... values) throws Exception { Class[] parameterTypes = new Class[values.length]; + for (int i = 0; i < values.length; i++) { parameterTypes[i] = values[i].getClass(); } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java index 8a87e6274..d62543c92 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,13 +39,13 @@ import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceProviderResolver; import javax.persistence.spi.PersistenceProviderResolverHolder; -import org.hibernate.ejb.HibernatePersistence; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.springframework.data.jpa.domain.sample.Category; import org.springframework.data.jpa.domain.sample.Order; import org.springframework.data.jpa.domain.sample.User; +import org.springframework.data.jpa.infrastructure.HibernateTestUtils; import org.springframework.data.mapping.PropertyPath; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -191,16 +191,16 @@ public class QueryUtilsIntegrationTests { } /** - * A {@link PersistenceProviderResolver} that returns only {@link HibernatePersistence} and ignores other - * {@link PersistenceProvider}s. + * A {@link PersistenceProviderResolver} that returns only a Hibernate {@link PersistenceProvider} and ignores others. * * @author Thomas Darimont + * @author Oliver Gierke */ static class HibernateOnlyPersistenceProviderResolver implements PersistenceProviderResolver { @Override public List getPersistenceProviders() { - return Arrays. asList(new HibernatePersistence()); + return Arrays.asList(HibernateTestUtils.getPersistenceProvider()); } @Override diff --git a/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java index c7966a75e..f875a2b0a 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import java.util.HashSet; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; -import org.hibernate.ejb.HibernatePersistence; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -32,6 +31,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.data.jpa.domain.sample.Category; import org.springframework.data.jpa.domain.sample.User; +import org.springframework.data.jpa.infrastructure.HibernateTestUtils; import org.springframework.data.jpa.repository.JpaContext; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; @@ -103,7 +103,7 @@ public class DefaultJpaContextIntegrationTests { private static final EntityManagerFactory createEntityManagerFactory(String persistenceUnitName) { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); - factoryBean.setPersistenceProvider(new HibernatePersistence()); + factoryBean.setPersistenceProvider(HibernateTestUtils.getPersistenceProvider()); factoryBean.setDataSource(new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build()); factoryBean.setPersistenceUnitName(persistenceUnitName); factoryBean.afterPropertiesSet();