Skip to content

Commit ba65cef

Browse files
committed
Upgrade Hibernate support baseline to 5.2+
Closes gh-25533 Closes gh-22326
1 parent b6d2a29 commit ba65cef

10 files changed

+50
-183
lines changed

spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateOperations.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -60,7 +60,7 @@
6060
* general {@link #execute} method and custom lambda blocks creating the queries,
6161
* ideally setting named parameters through {@link org.hibernate.query.Query}.
6262
* <b>Please be aware that deprecated operations are known to work with Hibernate
63-
* ORM 5.0-5.2 but may not work with Hibernate ORM 5.3 and higher anymore.</b>
63+
* ORM 5.2 but may not work with Hibernate ORM 5.3 and higher anymore.</b>
6464
*
6565
* @author Juergen Hoeller
6666
* @since 4.2

spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTemplate.java

+17-65
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.hibernate.SessionFactory;
4242
import org.hibernate.criterion.DetachedCriteria;
4343
import org.hibernate.criterion.Example;
44+
import org.hibernate.query.Query;
4445

4546
import org.springframework.beans.factory.InitializingBean;
4647
import org.springframework.dao.DataAccessException;
@@ -49,7 +50,6 @@
4950
import org.springframework.transaction.support.ResourceHolderSupport;
5051
import org.springframework.transaction.support.TransactionSynchronizationManager;
5152
import org.springframework.util.Assert;
52-
import org.springframework.util.ReflectionUtils;
5353

5454
/**
5555
* Helper class that simplifies Hibernate data access code. Automatically
@@ -90,23 +90,6 @@
9090
*/
9191
public class HibernateTemplate implements HibernateOperations, InitializingBean {
9292

93-
private static final Method createQueryMethod;
94-
95-
private static final Method getNamedQueryMethod;
96-
97-
static {
98-
// Hibernate 5.2's createQuery method declares a new subtype as return type,
99-
// so we need to use reflection for binary compatibility with 5.0/5.1 here.
100-
try {
101-
createQueryMethod = Session.class.getMethod("createQuery", String.class);
102-
getNamedQueryMethod = Session.class.getMethod("getNamedQuery", String.class);
103-
}
104-
catch (NoSuchMethodException ex) {
105-
throw new IllegalStateException("Incompatible Hibernate Session API", ex);
106-
}
107-
}
108-
109-
11093
protected final Log logger = LogFactory.getLog(getClass());
11194

11295
@Nullable
@@ -250,7 +233,7 @@ public boolean isCheckWriteOperations() {
250233
* <p>To specify the query region to be used for queries cached
251234
* by this template, set the "queryCacheRegion" property.
252235
* @see #setQueryCacheRegion
253-
* @see org.hibernate.Query#setCacheable
236+
* @see Query#setCacheable
254237
* @see Criteria#setCacheable
255238
*/
256239
public void setCacheQueries(boolean cacheQueries) {
@@ -271,7 +254,7 @@ public boolean isCacheQueries() {
271254
* <p>The cache region will not take effect unless queries created by this
272255
* template are configured to be cached via the "cacheQueries" property.
273256
* @see #setCacheQueries
274-
* @see org.hibernate.Query#setCacheRegion
257+
* @see Query#setCacheRegion
275258
* @see Criteria#setCacheRegion
276259
*/
277260
public void setQueryCacheRegion(@Nullable String queryCacheRegion) {
@@ -359,7 +342,6 @@ public <T> T executeWithNativeSession(HibernateCallback<T> action) {
359342
* @return a result object returned by the action, or {@code null}
360343
* @throws DataAccessException in case of Hibernate errors
361344
*/
362-
@SuppressWarnings("deprecation")
363345
@Nullable
364346
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException {
365347
Assert.notNull(action, "Callback object must not be null");
@@ -374,7 +356,7 @@ protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSess
374356
}
375357
if (session == null) {
376358
session = obtainSessionFactory().openSession();
377-
session.setFlushMode(FlushMode.MANUAL);
359+
session.setHibernateFlushMode(FlushMode.MANUAL);
378360
isNew = true;
379361
}
380362

@@ -543,7 +525,6 @@ public <T> List<T> loadAll(Class<T> entityClass) throws DataAccessException {
543525
}
544526

545527
@Override
546-
@SuppressWarnings({"deprecation"})
547528
public void load(Object entity, Serializable id) throws DataAccessException {
548529
executeWithNativeSession(session -> {
549530
session.load(entity, id);
@@ -887,11 +868,9 @@ public <T> List<T> findByExample(@Nullable String entityName, T exampleEntity, i
887868

888869
@Deprecated
889870
@Override
890-
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
891871
public List<?> find(String queryString, @Nullable Object... values) throws DataAccessException {
892872
return nonNull(executeWithNativeSession((HibernateCallback<List<?>>) session -> {
893-
org.hibernate.Query queryObject = queryObject(
894-
ReflectionUtils.invokeMethod(createQueryMethod, session, queryString));
873+
Query<?> queryObject = session.createQuery(queryString);
895874
prepareQuery(queryObject);
896875
if (values != null) {
897876
for (int i = 0; i < values.length; i++) {
@@ -912,16 +891,14 @@ public List<?> findByNamedParam(String queryString, String paramName, Object val
912891

913892
@Deprecated
914893
@Override
915-
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
916894
public List<?> findByNamedParam(String queryString, String[] paramNames, Object[] values)
917895
throws DataAccessException {
918896

919897
if (paramNames.length != values.length) {
920898
throw new IllegalArgumentException("Length of paramNames array must match length of values array");
921899
}
922900
return nonNull(executeWithNativeSession((HibernateCallback<List<?>>) session -> {
923-
org.hibernate.Query queryObject = queryObject(
924-
ReflectionUtils.invokeMethod(createQueryMethod, session, queryString));
901+
Query<?> queryObject = session.createQuery(queryString);
925902
prepareQuery(queryObject);
926903
for (int i = 0; i < values.length; i++) {
927904
applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
@@ -932,12 +909,9 @@ public List<?> findByNamedParam(String queryString, String[] paramNames, Object[
932909

933910
@Deprecated
934911
@Override
935-
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
936912
public List<?> findByValueBean(String queryString, Object valueBean) throws DataAccessException {
937-
938913
return nonNull(executeWithNativeSession((HibernateCallback<List<?>>) session -> {
939-
org.hibernate.Query queryObject = queryObject(
940-
ReflectionUtils.invokeMethod(createQueryMethod, session, queryString));
914+
Query<?> queryObject = session.createQuery(queryString);
941915
prepareQuery(queryObject);
942916
queryObject.setProperties(valueBean);
943917
return queryObject.list();
@@ -951,11 +925,9 @@ public List<?> findByValueBean(String queryString, Object valueBean) throws Data
951925

952926
@Deprecated
953927
@Override
954-
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
955928
public List<?> findByNamedQuery(String queryName, @Nullable Object... values) throws DataAccessException {
956929
return nonNull(executeWithNativeSession((HibernateCallback<List<?>>) session -> {
957-
org.hibernate.Query queryObject = queryObject(
958-
ReflectionUtils.invokeMethod(getNamedQueryMethod, session, queryName));
930+
Query<?> queryObject = session.getNamedQuery(queryName);
959931
prepareQuery(queryObject);
960932
if (values != null) {
961933
for (int i = 0; i < values.length; i++) {
@@ -976,7 +948,6 @@ public List<?> findByNamedQueryAndNamedParam(String queryName, String paramName,
976948

977949
@Deprecated
978950
@Override
979-
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
980951
public List<?> findByNamedQueryAndNamedParam(
981952
String queryName, @Nullable String[] paramNames, @Nullable Object[] values)
982953
throws DataAccessException {
@@ -985,8 +956,7 @@ public List<?> findByNamedQueryAndNamedParam(
985956
throw new IllegalArgumentException("Length of paramNames array must match length of values array");
986957
}
987958
return nonNull(executeWithNativeSession((HibernateCallback<List<?>>) session -> {
988-
org.hibernate.Query queryObject = (org.hibernate.Query)
989-
nonNull(ReflectionUtils.invokeMethod(getNamedQueryMethod, session, queryName));
959+
Query<?> queryObject = session.getNamedQuery(queryName);
990960
prepareQuery(queryObject);
991961
if (values != null) {
992962
for (int i = 0; i < values.length; i++) {
@@ -999,12 +969,9 @@ public List<?> findByNamedQueryAndNamedParam(
999969

1000970
@Deprecated
1001971
@Override
1002-
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
1003972
public List<?> findByNamedQueryAndValueBean(String queryName, Object valueBean) throws DataAccessException {
1004-
1005973
return nonNull(executeWithNativeSession((HibernateCallback<List<?>>) session -> {
1006-
org.hibernate.Query queryObject = queryObject(
1007-
ReflectionUtils.invokeMethod(getNamedQueryMethod, session, queryName));
974+
Query<?> queryObject = session.getNamedQuery(queryName);
1008975
prepareQuery(queryObject);
1009976
queryObject.setProperties(valueBean);
1010977
return queryObject.list();
@@ -1018,11 +985,9 @@ public List<?> findByNamedQueryAndValueBean(String queryName, Object valueBean)
1018985

1019986
@Deprecated
1020987
@Override
1021-
@SuppressWarnings({"rawtypes", "deprecation"})
1022988
public Iterator<?> iterate(String queryString, @Nullable Object... values) throws DataAccessException {
1023989
return nonNull(executeWithNativeSession((HibernateCallback<Iterator<?>>) session -> {
1024-
org.hibernate.Query queryObject = queryObject(
1025-
ReflectionUtils.invokeMethod(createQueryMethod, session, queryString));
990+
Query<?> queryObject = session.createQuery(queryString);
1026991
prepareQuery(queryObject);
1027992
if (values != null) {
1028993
for (int i = 0; i < values.length; i++) {
@@ -1046,11 +1011,9 @@ public void closeIterator(Iterator<?> it) throws DataAccessException {
10461011

10471012
@Deprecated
10481013
@Override
1049-
@SuppressWarnings({"rawtypes", "deprecation"})
10501014
public int bulkUpdate(String queryString, @Nullable Object... values) throws DataAccessException {
10511015
Integer result = executeWithNativeSession(session -> {
1052-
org.hibernate.Query queryObject = queryObject(
1053-
ReflectionUtils.invokeMethod(createQueryMethod, session, queryString));
1016+
Query<?> queryObject = session.createQuery(queryString);
10541017
prepareQuery(queryObject);
10551018
if (values != null) {
10561019
for (int i = 0; i < values.length; i++) {
@@ -1079,7 +1042,7 @@ public int bulkUpdate(String queryString, @Nullable Object... values) throws Dat
10791042
* @see FlushMode#MANUAL
10801043
*/
10811044
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
1082-
if (isCheckWriteOperations() && SessionFactoryUtils.getFlushMode(session).lessThan(FlushMode.COMMIT)) {
1045+
if (isCheckWriteOperations() && session.getHibernateFlushMode().lessThan(FlushMode.COMMIT)) {
10831046
throw new InvalidDataAccessApiUsageException(
10841047
"Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+
10851048
"Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
@@ -1121,8 +1084,7 @@ protected void prepareCriteria(Criteria criteria) {
11211084
* @see #setCacheQueries
11221085
* @see #setQueryCacheRegion
11231086
*/
1124-
@SuppressWarnings({"rawtypes", "deprecation"})
1125-
protected void prepareQuery(org.hibernate.Query queryObject) {
1087+
protected void prepareQuery(Query<?> queryObject) {
11261088
if (isCacheQueries()) {
11271089
queryObject.setCacheable(true);
11281090
if (getQueryCacheRegion() != null) {
@@ -1150,9 +1112,7 @@ protected void prepareQuery(org.hibernate.Query queryObject) {
11501112
* @param value the value of the parameter
11511113
* @throws HibernateException if thrown by the Query object
11521114
*/
1153-
@Deprecated
1154-
@SuppressWarnings({"rawtypes", "deprecation"})
1155-
protected void applyNamedParameterToQuery(org.hibernate.Query queryObject, String paramName, Object value)
1115+
protected void applyNamedParameterToQuery(Query<?> queryObject, String paramName, Object value)
11561116
throws HibernateException {
11571117

11581118
if (value instanceof Collection) {
@@ -1166,13 +1126,6 @@ else if (value instanceof Object[]) {
11661126
}
11671127
}
11681128

1169-
@Deprecated
1170-
@SuppressWarnings({"rawtypes", "deprecation"})
1171-
private static org.hibernate.Query queryObject(@Nullable Object result) {
1172-
Assert.state(result != null, "No Hibernate Query");
1173-
return (org.hibernate.Query) result;
1174-
}
1175-
11761129
private static <T> T nonNull(@Nullable T result) {
11771130
Assert.state(result != null, "No result");
11781131
return result;
@@ -1193,7 +1146,6 @@ public CloseSuppressingInvocationHandler(Session target) {
11931146
}
11941147

11951148
@Override
1196-
@SuppressWarnings({"rawtypes", "deprecation"})
11971149
@Nullable
11981150
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
11991151
// Invocation on Session interface coming in...
@@ -1219,8 +1171,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
12191171
if (retVal instanceof Criteria) {
12201172
prepareCriteria(((Criteria) retVal));
12211173
}
1222-
else if (retVal instanceof org.hibernate.Query) {
1223-
prepareQuery(((org.hibernate.Query) retVal));
1174+
else if (retVal instanceof Query) {
1175+
prepareQuery(((Query<?>) retVal));
12241176
}
12251177

12261178
return retVal;

spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
533533

534534
if (!definition.isReadOnly() && !txObject.isNewSession()) {
535535
// We need AUTO or COMMIT for a non-read-only transaction.
536-
FlushMode flushMode = SessionFactoryUtils.getFlushMode(session);
536+
FlushMode flushMode = session.getHibernateFlushMode();
537537
if (FlushMode.MANUAL.equals(flushMode)) {
538538
session.setFlushMode(FlushMode.AUTO);
539539
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
@@ -562,10 +562,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
562562
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
563563
if (getDataSource() != null) {
564564
SessionImplementor sessionImpl = (SessionImplementor) session;
565-
// The following needs to use a lambda expression instead of a method reference
566-
// for compatibility with Hibernate ORM <5.2 where connection() is defined on
567-
// SessionImplementor itself instead of on SharedSessionContractImplementor...
568-
ConnectionHolder conHolder = new ConnectionHolder(() -> sessionImpl.connection());
565+
ConnectionHolder conHolder = new ConnectionHolder(sessionImpl::connection);
569566
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
570567
conHolder.setTimeoutInSeconds(timeout);
571568
}

spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858
* way to set up a shared Hibernate SessionFactory in a Spring application context; the
5959
* SessionFactory can then be passed to data access objects via dependency injection.
6060
*
61-
* <p>Compatible with Hibernate 5.0/5.1 as well as 5.2/5.3/5.4, as of Spring 5.2.
62-
* Set up with Hibernate 5.2+, {@code LocalSessionFactoryBean} is an immediate alternative
61+
* <p>Compatible with Hibernate 5.2/5.3/5.4, as of Spring 5.3.
62+
* This Hibernate-specific {@code LocalSessionFactoryBean} can be an immediate alternative
6363
* to {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean} for common
6464
* JPA purposes: In particular with Hibernate 5.3/5.4, the Hibernate {@code SessionFactory}
6565
* will natively expose the JPA {@code EntityManagerFactory} interface as well, and

spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java

+7-35
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
4848
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
4949
import org.hibernate.engine.spi.SessionFactoryImplementor;
50+
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
5051

5152
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
5253
import org.springframework.core.InfrastructureProxy;
@@ -76,8 +77,8 @@
7677
* Typically combined with {@link HibernateTransactionManager} for declarative
7778
* transactions against the {@code SessionFactory} and its JDBC {@code DataSource}.
7879
*
79-
* <p>Compatible with Hibernate 5.0/5.1 as well as 5.2/5.3/5.4, as of Spring 5.2.
80-
* Set up with Hibernate 5.2+, this builder is also a convenient way to set up
80+
* <p>Compatible with Hibernate 5.2/5.3/5.4, as of Spring 5.3.
81+
* This Hibernate-specific factory builder can also be a convenient way to set up
8182
* a JPA {@code EntityManagerFactory} since the Hibernate {@code SessionFactory}
8283
* natively exposes the JPA {@code EntityManagerFactory} interface as well now.
8384
*
@@ -162,23 +163,8 @@ public LocalSessionFactoryBuilder(
162163
if (dataSource != null) {
163164
getProperties().put(AvailableSettings.DATASOURCE, dataSource);
164165
}
165-
166-
// Hibernate 5.1/5.2: manually enforce connection release mode ON_CLOSE (the former default)
167-
try {
168-
// Try Hibernate 5.2
169-
AvailableSettings.class.getField("CONNECTION_HANDLING");
170-
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD");
171-
}
172-
catch (NoSuchFieldException ex) {
173-
// Try Hibernate 5.1
174-
try {
175-
AvailableSettings.class.getField("ACQUIRE_CONNECTIONS");
176-
getProperties().put("hibernate.connection.release_mode", "ON_CLOSE");
177-
}
178-
catch (NoSuchFieldException ex2) {
179-
// on Hibernate 5.0.x or lower - no need to change the default there
180-
}
181-
}
166+
getProperties().put(AvailableSettings.CONNECTION_HANDLING,
167+
PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_HOLD);
182168

183169
getProperties().put(AvailableSettings.CLASSLOADERS, Collections.singleton(resourceLoader.getClassLoader()));
184170
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
@@ -225,22 +211,8 @@ else if (jtaTransactionManager instanceof TransactionManager) {
225211
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
226212
}
227213

228-
// Hibernate 5.1/5.2: manually enforce connection release mode AFTER_STATEMENT (the JTA default)
229-
try {
230-
// Try Hibernate 5.2
231-
AvailableSettings.class.getField("CONNECTION_HANDLING");
232-
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT");
233-
}
234-
catch (NoSuchFieldException ex) {
235-
// Try Hibernate 5.1
236-
try {
237-
AvailableSettings.class.getField("ACQUIRE_CONNECTIONS");
238-
getProperties().put("hibernate.connection.release_mode", "AFTER_STATEMENT");
239-
}
240-
catch (NoSuchFieldException ex2) {
241-
// on Hibernate 5.0.x or lower - no need to change the default there
242-
}
243-
}
214+
getProperties().put(AvailableSettings.CONNECTION_HANDLING,
215+
PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT);
244216

245217
return this;
246218
}

0 commit comments

Comments
 (0)