Skip to content

Commit d52d9fd

Browse files
committed
HibernateJpaVendorAdapter preserves connection release mode for JTA
Issue: SPR-16162
1 parent f861f18 commit d52d9fd

File tree

5 files changed

+105
-42
lines changed

5 files changed

+105
-42
lines changed

spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java

+33-18
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
import org.springframework.core.task.AsyncTaskExecutor;
5656
import org.springframework.dao.DataAccessException;
5757
import org.springframework.dao.support.PersistenceExceptionTranslator;
58-
import org.springframework.util.Assert;
5958
import org.springframework.util.ClassUtils;
6059
import org.springframework.util.CollectionUtils;
6160

@@ -264,8 +263,8 @@ public void setJpaVendorAdapter(JpaVendorAdapter jpaVendorAdapter) {
264263
}
265264

266265
/**
267-
* Return the JpaVendorAdapter implementation for this
268-
* EntityManagerFactory, or {@code null} if not known.
266+
* Return the JpaVendorAdapter implementation for this EntityManagerFactory,
267+
* or {@code null} if not known.
269268
*/
270269
public JpaVendorAdapter getJpaVendorAdapter() {
271270
return this.jpaVendorAdapter;
@@ -317,33 +316,46 @@ public void setBeanName(String name) {
317316

318317

319318
@Override
320-
public final void afterPropertiesSet() throws PersistenceException {
321-
if (this.jpaVendorAdapter != null) {
319+
public void afterPropertiesSet() throws PersistenceException {
320+
JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
321+
if (jpaVendorAdapter != null) {
322322
if (this.persistenceProvider == null) {
323-
this.persistenceProvider = this.jpaVendorAdapter.getPersistenceProvider();
323+
this.persistenceProvider = jpaVendorAdapter.getPersistenceProvider();
324324
}
325-
Map<String, ?> vendorPropertyMap = this.jpaVendorAdapter.getJpaPropertyMap();
326-
if (vendorPropertyMap != null) {
325+
PersistenceUnitInfo pui = getPersistenceUnitInfo();
326+
Map<String, ?> vendorPropertyMap = null;
327+
if (pui != null) {
328+
try {
329+
vendorPropertyMap = jpaVendorAdapter.getJpaPropertyMap(pui);
330+
}
331+
catch (AbstractMethodError err) {
332+
// Spring 4.3.13 getJpaPropertyMap(PersistenceUnitInfo) not implemented
333+
}
334+
}
335+
if (vendorPropertyMap == null) {
336+
vendorPropertyMap = jpaVendorAdapter.getJpaPropertyMap();
337+
}
338+
if (!CollectionUtils.isEmpty(vendorPropertyMap)) {
327339
for (Map.Entry<String, ?> entry : vendorPropertyMap.entrySet()) {
328340
if (!this.jpaPropertyMap.containsKey(entry.getKey())) {
329341
this.jpaPropertyMap.put(entry.getKey(), entry.getValue());
330342
}
331343
}
332344
}
333345
if (this.entityManagerFactoryInterface == null) {
334-
this.entityManagerFactoryInterface = this.jpaVendorAdapter.getEntityManagerFactoryInterface();
346+
this.entityManagerFactoryInterface = jpaVendorAdapter.getEntityManagerFactoryInterface();
335347
if (!ClassUtils.isVisible(this.entityManagerFactoryInterface, this.beanClassLoader)) {
336348
this.entityManagerFactoryInterface = EntityManagerFactory.class;
337349
}
338350
}
339351
if (this.entityManagerInterface == null) {
340-
this.entityManagerInterface = this.jpaVendorAdapter.getEntityManagerInterface();
352+
this.entityManagerInterface = jpaVendorAdapter.getEntityManagerInterface();
341353
if (!ClassUtils.isVisible(this.entityManagerInterface, this.beanClassLoader)) {
342354
this.entityManagerInterface = EntityManager.class;
343355
}
344356
}
345357
if (this.jpaDialect == null) {
346-
this.jpaDialect = this.jpaVendorAdapter.getJpaDialect();
358+
this.jpaDialect = jpaVendorAdapter.getJpaDialect();
347359
}
348360
}
349361

@@ -372,8 +384,9 @@ private EntityManagerFactory buildNativeEntityManagerFactory() {
372384
throw new IllegalStateException(
373385
"JPA PersistenceProvider returned null EntityManagerFactory - check your JPA provider setup!");
374386
}
375-
if (this.jpaVendorAdapter != null) {
376-
this.jpaVendorAdapter.postProcessEntityManagerFactory(emf);
387+
JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
388+
if (jpaVendorAdapter != null) {
389+
jpaVendorAdapter.postProcessEntityManagerFactory(emf);
377390
}
378391
if (logger.isInfoEnabled()) {
379392
logger.info("Initialized JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'");
@@ -390,8 +403,9 @@ private EntityManagerFactory buildNativeEntityManagerFactory() {
390403
*/
391404
protected EntityManagerFactory createEntityManagerFactoryProxy(EntityManagerFactory emf) {
392405
Set<Class<?>> ifcs = new LinkedHashSet<Class<?>>();
393-
if (this.entityManagerFactoryInterface != null) {
394-
ifcs.add(this.entityManagerFactoryInterface);
406+
Class<?> entityManagerFactoryInterface = this.entityManagerFactoryInterface;
407+
if (entityManagerFactoryInterface != null) {
408+
ifcs.add(entityManagerFactoryInterface);
395409
}
396410
else if (emf != null) {
397411
ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(emf.getClass(), this.beanClassLoader));
@@ -406,8 +420,8 @@ else if (emf != null) {
406420
new ManagedEntityManagerFactoryInvocationHandler(this));
407421
}
408422
catch (IllegalArgumentException ex) {
409-
if (this.entityManagerFactoryInterface != null) {
410-
throw new IllegalStateException("EntityManagerFactory interface [" + this.entityManagerFactoryInterface +
423+
if (entityManagerFactoryInterface != null) {
424+
throw new IllegalStateException("EntityManagerFactory interface [" + entityManagerFactoryInterface +
411425
"] seems to conflict with Spring's EntityManagerFactoryInfo mixin - consider resetting the "+
412426
"'entityManagerFactoryInterface' property to plain [javax.persistence.EntityManagerFactory]", ex);
413427
}
@@ -485,7 +499,8 @@ else if (method.getName().equals("createEntityManager") && args != null && args.
485499
*/
486500
@Override
487501
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
488-
return (this.jpaDialect != null ? this.jpaDialect.translateExceptionIfPossible(ex) :
502+
JpaDialect jpaDialect = getJpaDialect();
503+
return (jpaDialect != null ? jpaDialect.translateExceptionIfPossible(ex) :
489504
EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex));
490505
}
491506

spring-orm/src/main/java/org/springframework/orm/jpa/JpaVendorAdapter.java

+33-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -20,6 +20,7 @@
2020
import javax.persistence.EntityManager;
2121
import javax.persistence.EntityManagerFactory;
2222
import javax.persistence.spi.PersistenceProvider;
23+
import javax.persistence.spi.PersistenceUnitInfo;
2324

2425
/**
2526
* SPI interface that allows to plug in vendor-specific behavior
@@ -46,17 +47,40 @@ public interface JpaVendorAdapter {
4647
*/
4748
String getPersistenceProviderRootPackage();
4849

50+
/**
51+
* Return a Map of vendor-specific JPA properties for the given persistence
52+
* unit, typically based on settings in this JpaVendorAdapter instance.
53+
* <p>Note that there might be further JPA properties defined on the
54+
* EntityManagerFactory bean, which might potentially override individual
55+
* JPA property values specified here.
56+
* <p>This implementation delegates to {@link #getJpaPropertyMap()} for
57+
* non-unit-dependent properties. Effectively, this PersistenceUnitInfo-based
58+
* variant only needs to be implemented if there is an actual need to react
59+
* to unit-specific characteristics such as the transaction type.
60+
* <p><b>NOTE:</b> This variant will only be invoked in case of Java EE style
61+
* container bootstrapping where a {@link PersistenceUnitInfo} is present
62+
* (i.e. {@link LocalContainerEntityManagerFactoryBean}. In case of simple
63+
* Java SE style bootstrapping via {@link javax.persistence.Persistence}
64+
* (i.e. {@link LocalEntityManagerFactoryBean}), the parameter-less
65+
* {@link #getJpaPropertyMap()} variant will be called directly.
66+
* @param pui the PersistenceUnitInfo for the current persistence unit
67+
* @return a Map of JPA properties, as accepted by the standard JPA bootstrap
68+
* facilities, or an empty Map if there are no properties to expose
69+
* @since 4.3.13
70+
* @see PersistenceUnitInfo#getTransactionType()
71+
* @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo, Map)
72+
*/
73+
Map<String, ?> getJpaPropertyMap(PersistenceUnitInfo pui);
74+
4975
/**
5076
* Return a Map of vendor-specific JPA properties,
5177
* typically based on settings in this JpaVendorAdapter instance.
52-
* <p>Note that there might be further JPA properties defined on
53-
* the EntityManagerFactory bean, which might potentially override
54-
* individual JPA property values specified here.
55-
* @return a Map of JPA properties, as accepted by the standard
56-
* JPA bootstrap facilities, or {@code null} or an empty Map
57-
* if there are no such properties to expose
58-
* @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
59-
* @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
78+
* <p>Note that there might be further JPA properties defined on the
79+
* EntityManagerFactory bean, which might potentially override individual
80+
* JPA property values specified here.
81+
* @return a Map of JPA properties, as accepted by the standard JPA bootstrap
82+
* facilities, or an empty Map if there are no properties to expose
83+
* @see javax.persistence.Persistence#createEntityManagerFactory(String, Map)
6084
*/
6185
Map<String, ?> getJpaPropertyMap();
6286

spring-orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -34,6 +34,7 @@
3434
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
3535
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
3636
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
37+
import org.springframework.util.Assert;
3738
import org.springframework.util.ClassUtils;
3839

3940
/**
@@ -91,8 +92,7 @@ public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManage
9192

9293
private PersistenceUnitManager persistenceUnitManager;
9394

94-
private final DefaultPersistenceUnitManager internalPersistenceUnitManager =
95-
new DefaultPersistenceUnitManager();
95+
private final DefaultPersistenceUnitManager internalPersistenceUnitManager = new DefaultPersistenceUnitManager();
9696

9797
private PersistenceUnitInfo persistenceUnitInfo;
9898

@@ -319,7 +319,7 @@ public void setResourceLoader(ResourceLoader resourceLoader) {
319319

320320

321321
@Override
322-
protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
322+
public void afterPropertiesSet() throws PersistenceException {
323323
PersistenceUnitManager managerToUse = this.persistenceUnitManager;
324324
if (this.persistenceUnitManager == null) {
325325
this.internalPersistenceUnitManager.afterPropertiesSet();
@@ -333,6 +333,13 @@ protected EntityManagerFactory createNativeEntityManagerFactory() throws Persist
333333
jpaVendorAdapter.getPersistenceProviderRootPackage());
334334
}
335335

336+
super.afterPropertiesSet();
337+
}
338+
339+
@Override
340+
protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
341+
Assert.state(this.persistenceUnitInfo != null, "PersistenceUnitInfo not initialized");
342+
336343
PersistenceProvider provider = getPersistenceProvider();
337344
if (provider == null) {
338345
String providerClassName = this.persistenceUnitInfo.getPersistenceProviderClassName();

spring-orm/src/main/java/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -16,9 +16,11 @@
1616

1717
package org.springframework.orm.jpa.vendor;
1818

19+
import java.util.Collections;
1920
import java.util.Map;
2021
import javax.persistence.EntityManager;
2122
import javax.persistence.EntityManagerFactory;
23+
import javax.persistence.spi.PersistenceUnitInfo;
2224

2325
import org.springframework.orm.jpa.JpaDialect;
2426
import org.springframework.orm.jpa.JpaVendorAdapter;
@@ -119,9 +121,14 @@ public String getPersistenceProviderRootPackage() {
119121
return null;
120122
}
121123

124+
@Override
125+
public Map<String, ?> getJpaPropertyMap(PersistenceUnitInfo pui) {
126+
return getJpaPropertyMap();
127+
}
128+
122129
@Override
123130
public Map<String, ?> getJpaPropertyMap() {
124-
return null;
131+
return Collections.emptyMap();
125132
}
126133

127134
@Override
@@ -139,10 +146,6 @@ public Class<? extends EntityManager> getEntityManagerInterface() {
139146
return EntityManager.class;
140147
}
141148

142-
/**
143-
* Post-process the EntityManagerFactory after it has been initialized.
144-
* @param emf the EntityManagerFactory to process
145-
*/
146149
@Override
147150
public void postProcessEntityManagerFactory(EntityManagerFactory emf) {
148151
}

spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java

+19-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import javax.persistence.EntityManager;
2222
import javax.persistence.EntityManagerFactory;
2323
import javax.persistence.spi.PersistenceProvider;
24+
import javax.persistence.spi.PersistenceUnitInfo;
25+
import javax.persistence.spi.PersistenceUnitTransactionType;
2426

2527
import org.hibernate.cfg.Environment;
2628
import org.hibernate.dialect.DB2Dialect;
@@ -113,13 +115,15 @@ public HibernateJpaVendorAdapter() {
113115
* new connection handling mode {@code DELAYED_ACQUISITION_AND_HOLD} in that case
114116
* unless a user-specified connection handling mode property indicates otherwise;
115117
* switch this flag to {@code false} to avoid that interference.
116-
* <p><b>NOTE: Per the explanation above, you may have to turn this flag off
117-
* when using Hibernate in a JTA environment, e.g. on WebLogic.</b> Alternatively,
118-
* set Hibernate 5.2's "hibernate.connection.handling_mode" property to
119-
* "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION" or even
118+
* <p><b>NOTE: For a persistence unit with transaction type JTA e.g. on WebLogic,
119+
* the connection release mode will never be altered from its provider default,
120+
* i.e. not be forced to {@code DELAYED_ACQUISITION_AND_HOLD} by this flag.</b>
121+
* Alternatively, set Hibernate 5.2's "hibernate.connection.handling_mode"
122+
* property to "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION" or even
120123
* "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT" in such a scenario.
121124
* @since 4.3.1
122-
* @see #getJpaPropertyMap()
125+
* @see PersistenceUnitInfo#getTransactionType()
126+
* @see #getJpaPropertyMap(PersistenceUnitInfo)
123127
* @see HibernateJpaDialect#beginTransaction
124128
*/
125129
public void setPrepareConnection(boolean prepareConnection) {
@@ -137,8 +141,18 @@ public String getPersistenceProviderRootPackage() {
137141
return "org.hibernate";
138142
}
139143

144+
@Override
145+
public Map<String, Object> getJpaPropertyMap(PersistenceUnitInfo pui) {
146+
return buildJpaPropertyMap(this.jpaDialect.prepareConnection &&
147+
pui.getTransactionType() != PersistenceUnitTransactionType.JTA);
148+
}
149+
140150
@Override
141151
public Map<String, Object> getJpaPropertyMap() {
152+
return buildJpaPropertyMap(this.jpaDialect.prepareConnection);
153+
}
154+
155+
private Map<String, Object> buildJpaPropertyMap(boolean connectionReleaseOnClose) {
142156
Map<String, Object> jpaProperties = new HashMap<String, Object>();
143157

144158
if (getDatabasePlatform() != null) {

0 commit comments

Comments
 (0)