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
This commit is contained in:
Oliver Gierke
2016-06-03 19:33:07 +02:00
parent 068a5d52f1
commit a584c74c62
8 changed files with 151 additions and 21 deletions

10
pom.xml
View File

@@ -23,6 +23,7 @@
<eclipselink>2.6.2</eclipselink>
<hibernate>3.6.10.Final</hibernate>
<hibernate.artifact>hibernate-entitymanager</hibernate.artifact>
<hsqldb1>1.8.0.10</hsqldb1>
<jpa>2.0.0</jpa>
<openjpa>2.4.1</openjpa>
@@ -111,6 +112,13 @@
</repository>
</repositories>
</profile>
<profile>
<id>hibernate-52</id>
<properties>
<hibernate>5.2.0.Final</hibernate>
<hibernate.artifact>hibernate-core</hibernate.artifact>
</properties>
</profile>
<profile>
<id>eclipselink-next</id>
<properties>
@@ -250,7 +258,7 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<artifactId>${hibernate.artifact}</artifactId>
<version>${hibernate}</version>
<optional>true</optional>
</dependency>

View File

@@ -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<String> 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();
}
}

View File

@@ -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);
}
/**

View File

@@ -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<String> 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!");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 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"));

View File

@@ -33,17 +33,16 @@ import javax.persistence.Query;
import javax.persistence.TemporalType;
import org.hibernate.Version;
import org.hibernate.ejb.HibernateQuery;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.data.annotation.PersistenceConstructor;
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.projection.SpelAwareProxyProjectionFactory;
@@ -114,22 +113,21 @@ 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();
}
Method method = UserRepository.class.getMethod(methodName, parameterTypes);
JpaQueryMethod queryMethod = getQueryMethod(methodName, parameterTypes);
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager,
PersistenceProvider.fromEntityManager(entityManager));

View File

@@ -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<PersistenceProvider> getPersistenceProviders() {
return Arrays.<PersistenceProvider> asList(new HibernatePersistence());
return Arrays.asList(HibernateTestUtils.getPersistenceProvider());
}
@Override

View File

@@ -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;
@@ -40,6 +39,7 @@ import org.springframework.context.annotation.FilterType;
import org.springframework.context.support.ClassPathXmlApplicationContext;
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.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
@@ -147,7 +147,7 @@ public class DefaultJpaContextIntegrationTests {
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);