Skip to content

Commit bd02edf

Browse files
committed
Configure JPA only if a single datasource is available
This commit changes HibernateJpaAutoConfiguration to back off if no single datasource candidate is available in the context. Closes gh-5541
1 parent 8656512 commit bd02edf

File tree

4 files changed

+296
-172
lines changed

4 files changed

+296
-172
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java

+5-152
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,9 @@
1717
package org.springframework.boot.autoconfigure.orm.jpa;
1818

1919
import java.util.Arrays;
20-
import java.util.Collections;
21-
import java.util.LinkedHashMap;
22-
import java.util.List;
23-
import java.util.Map;
2420

2521
import javax.persistence.EntityManager;
26-
import javax.sql.DataSource;
2722

28-
import org.apache.commons.logging.Log;
29-
import org.apache.commons.logging.LogFactory;
30-
31-
import org.springframework.beans.factory.ObjectProvider;
3223
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3324
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3425
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
@@ -38,20 +29,15 @@
3829
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
3930
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
4031
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.HibernateEntityManagerCondition;
41-
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
42-
import org.springframework.boot.jdbc.SchemaManagementProvider;
43-
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
32+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4433
import org.springframework.context.annotation.ConditionContext;
4534
import org.springframework.context.annotation.Conditional;
4635
import org.springframework.context.annotation.Configuration;
36+
import org.springframework.context.annotation.Import;
4737
import org.springframework.core.Ordered;
4838
import org.springframework.core.annotation.Order;
4939
import org.springframework.core.type.AnnotatedTypeMetadata;
50-
import org.springframework.jndi.JndiLocatorDelegate;
5140
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
52-
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
53-
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
54-
import org.springframework.transaction.jta.JtaTransactionManager;
5541
import org.springframework.util.ClassUtils;
5642

5743
/**
@@ -65,143 +51,10 @@
6551
@Configuration
6652
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class })
6753
@Conditional(HibernateEntityManagerCondition.class)
54+
@EnableConfigurationProperties(JpaProperties.class)
6855
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
69-
public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
70-
71-
private static final Log logger = LogFactory
72-
.getLog(HibernateJpaAutoConfiguration.class);
73-
74-
private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";
75-
76-
/**
77-
* {@code NoJtaPlatform} implementations for various Hibernate versions.
78-
*/
79-
private static final String[] NO_JTA_PLATFORM_CLASSES = {
80-
"org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform",
81-
"org.hibernate.service.jta.platform.internal.NoJtaPlatform" };
82-
83-
/**
84-
* {@code WebSphereExtendedJtaPlatform} implementations for various Hibernate
85-
* versions.
86-
*/
87-
private static final String[] WEBSPHERE_JTA_PLATFORM_CLASSES = {
88-
"org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform",
89-
"org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform", };
90-
91-
private final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider;
92-
93-
public HibernateJpaAutoConfiguration(DataSource dataSource,
94-
JpaProperties jpaProperties,
95-
ObjectProvider<JtaTransactionManager> jtaTransactionManager,
96-
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
97-
ObjectProvider<List<SchemaManagementProvider>> providers) {
98-
super(dataSource, jpaProperties, jtaTransactionManager,
99-
transactionManagerCustomizers);
100-
this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(
101-
providers.getIfAvailable(Collections::emptyList));
102-
}
103-
104-
@Override
105-
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
106-
return new HibernateJpaVendorAdapter();
107-
}
108-
109-
@Override
110-
protected Map<String, Object> getVendorProperties() {
111-
Map<String, Object> vendorProperties = new LinkedHashMap<>();
112-
String defaultDdlMode = this.defaultDdlAutoProvider
113-
.getDefaultDdlAuto(getDataSource());
114-
vendorProperties.putAll(getProperties().getHibernateProperties(defaultDdlMode));
115-
return vendorProperties;
116-
}
117-
118-
@Override
119-
protected void customizeVendorProperties(Map<String, Object> vendorProperties) {
120-
super.customizeVendorProperties(vendorProperties);
121-
if (!vendorProperties.containsKey(JTA_PLATFORM)) {
122-
configureJtaPlatform(vendorProperties);
123-
}
124-
}
125-
126-
private void configureJtaPlatform(Map<String, Object> vendorProperties)
127-
throws LinkageError {
128-
JtaTransactionManager jtaTransactionManager = getJtaTransactionManager();
129-
if (jtaTransactionManager != null) {
130-
if (runningOnWebSphere()) {
131-
// We can never use SpringJtaPlatform on WebSphere as
132-
// WebSphereUowTransactionManager has a null TransactionManager
133-
// which will cause Hibernate to NPE
134-
configureWebSphereTransactionPlatform(vendorProperties);
135-
}
136-
else {
137-
configureSpringJtaPlatform(vendorProperties, jtaTransactionManager);
138-
}
139-
}
140-
else {
141-
vendorProperties.put(JTA_PLATFORM, getNoJtaPlatformManager());
142-
}
143-
}
144-
145-
private boolean runningOnWebSphere() {
146-
return ClassUtils.isPresent(
147-
"com.ibm.websphere.jtaextensions." + "ExtendedJTATransaction",
148-
getClass().getClassLoader());
149-
}
150-
151-
private void configureWebSphereTransactionPlatform(
152-
Map<String, Object> vendorProperties) {
153-
vendorProperties.put(JTA_PLATFORM, getWebSphereJtaPlatformManager());
154-
}
155-
156-
private Object getWebSphereJtaPlatformManager() {
157-
return getJtaPlatformManager(WEBSPHERE_JTA_PLATFORM_CLASSES);
158-
}
159-
160-
private void configureSpringJtaPlatform(Map<String, Object> vendorProperties,
161-
JtaTransactionManager jtaTransactionManager) {
162-
try {
163-
vendorProperties.put(JTA_PLATFORM,
164-
new SpringJtaPlatform(jtaTransactionManager));
165-
}
166-
catch (LinkageError ex) {
167-
// NoClassDefFoundError can happen if Hibernate 4.2 is used and some
168-
// containers (e.g. JBoss EAP 6) wraps it in the superclass LinkageError
169-
if (!isUsingJndi()) {
170-
throw new IllegalStateException("Unable to set Hibernate JTA "
171-
+ "platform, are you using the correct "
172-
+ "version of Hibernate?", ex);
173-
}
174-
// Assume that Hibernate will use JNDI
175-
if (logger.isDebugEnabled()) {
176-
logger.debug("Unable to set Hibernate JTA platform : " + ex.getMessage());
177-
}
178-
}
179-
}
180-
181-
private boolean isUsingJndi() {
182-
try {
183-
return JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable();
184-
}
185-
catch (Error ex) {
186-
return false;
187-
}
188-
}
189-
190-
private Object getNoJtaPlatformManager() {
191-
return getJtaPlatformManager(NO_JTA_PLATFORM_CLASSES);
192-
}
193-
194-
private Object getJtaPlatformManager(String[] candidates) {
195-
for (String candidate : candidates) {
196-
try {
197-
return Class.forName(candidate).newInstance();
198-
}
199-
catch (Exception ex) {
200-
// Continue searching
201-
}
202-
}
203-
throw new IllegalStateException("Could not configure JTA platform");
204-
}
56+
@Import(JpaHibernateConfiguration.class)
57+
public class HibernateJpaAutoConfiguration {
20558

20659
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
20760
static class HibernateEntityManagerCondition extends SpringBootCondition {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.orm.jpa;
18+
19+
import java.util.Collections;
20+
import java.util.LinkedHashMap;
21+
import java.util.List;
22+
import java.util.Map;
23+
24+
import javax.sql.DataSource;
25+
26+
import org.apache.commons.logging.Log;
27+
import org.apache.commons.logging.LogFactory;
28+
29+
import org.springframework.beans.factory.ObjectProvider;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
31+
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
32+
import org.springframework.boot.jdbc.SchemaManagementProvider;
33+
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
34+
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.jndi.JndiLocatorDelegate;
36+
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
37+
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
38+
import org.springframework.transaction.jta.JtaTransactionManager;
39+
import org.springframework.util.ClassUtils;
40+
41+
/**
42+
* {@link JpaBaseConfiguration} implementation for Hibernate.
43+
*
44+
* @author Phillip Webb
45+
* @author Josh Long
46+
* @author Manuel Doninger
47+
* @author Andy Wilkinson
48+
* @author Stephane Nicoll
49+
* @since 2.0.0
50+
*/
51+
@Configuration
52+
@ConditionalOnSingleCandidate(DataSource.class)
53+
public class JpaHibernateConfiguration extends JpaBaseConfiguration {
54+
55+
private static final Log logger = LogFactory
56+
.getLog(JpaHibernateConfiguration.class);
57+
58+
private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";
59+
60+
/**
61+
* {@code NoJtaPlatform} implementations for various Hibernate versions.
62+
*/
63+
private static final String[] NO_JTA_PLATFORM_CLASSES = {
64+
"org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform",
65+
"org.hibernate.service.jta.platform.internal.NoJtaPlatform" };
66+
67+
/**
68+
* {@code WebSphereExtendedJtaPlatform} implementations for various Hibernate
69+
* versions.
70+
*/
71+
private static final String[] WEBSPHERE_JTA_PLATFORM_CLASSES = {
72+
"org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform",
73+
"org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform", };
74+
75+
private final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider;
76+
77+
public JpaHibernateConfiguration(DataSource dataSource,
78+
JpaProperties jpaProperties,
79+
ObjectProvider<JtaTransactionManager> jtaTransactionManager,
80+
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers,
81+
ObjectProvider<List<SchemaManagementProvider>> providers) {
82+
super(dataSource, jpaProperties, jtaTransactionManager,
83+
transactionManagerCustomizers);
84+
this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(
85+
providers.getIfAvailable(Collections::emptyList));
86+
}
87+
88+
@Override
89+
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
90+
return new HibernateJpaVendorAdapter();
91+
}
92+
93+
@Override
94+
protected Map<String, Object> getVendorProperties() {
95+
Map<String, Object> vendorProperties = new LinkedHashMap<>();
96+
String defaultDdlMode = this.defaultDdlAutoProvider
97+
.getDefaultDdlAuto(getDataSource());
98+
vendorProperties.putAll(getProperties().getHibernateProperties(defaultDdlMode));
99+
return vendorProperties;
100+
}
101+
102+
@Override
103+
protected void customizeVendorProperties(Map<String, Object> vendorProperties) {
104+
super.customizeVendorProperties(vendorProperties);
105+
if (!vendorProperties.containsKey(JTA_PLATFORM)) {
106+
configureJtaPlatform(vendorProperties);
107+
}
108+
}
109+
110+
private void configureJtaPlatform(Map<String, Object> vendorProperties)
111+
throws LinkageError {
112+
JtaTransactionManager jtaTransactionManager = getJtaTransactionManager();
113+
if (jtaTransactionManager != null) {
114+
if (runningOnWebSphere()) {
115+
// We can never use SpringJtaPlatform on WebSphere as
116+
// WebSphereUowTransactionManager has a null TransactionManager
117+
// which will cause Hibernate to NPE
118+
configureWebSphereTransactionPlatform(vendorProperties);
119+
}
120+
else {
121+
configureSpringJtaPlatform(vendorProperties, jtaTransactionManager);
122+
}
123+
}
124+
else {
125+
vendorProperties.put(JTA_PLATFORM, getNoJtaPlatformManager());
126+
}
127+
}
128+
129+
private boolean runningOnWebSphere() {
130+
return ClassUtils.isPresent(
131+
"com.ibm.websphere.jtaextensions." + "ExtendedJTATransaction",
132+
getClass().getClassLoader());
133+
}
134+
135+
private void configureWebSphereTransactionPlatform(
136+
Map<String, Object> vendorProperties) {
137+
vendorProperties.put(JTA_PLATFORM, getWebSphereJtaPlatformManager());
138+
}
139+
140+
private Object getWebSphereJtaPlatformManager() {
141+
return getJtaPlatformManager(WEBSPHERE_JTA_PLATFORM_CLASSES);
142+
}
143+
144+
private void configureSpringJtaPlatform(Map<String, Object> vendorProperties,
145+
JtaTransactionManager jtaTransactionManager) {
146+
try {
147+
vendorProperties.put(JTA_PLATFORM,
148+
new SpringJtaPlatform(jtaTransactionManager));
149+
}
150+
catch (LinkageError ex) {
151+
// NoClassDefFoundError can happen if Hibernate 4.2 is used and some
152+
// containers (e.g. JBoss EAP 6) wraps it in the superclass LinkageError
153+
if (!isUsingJndi()) {
154+
throw new IllegalStateException("Unable to set Hibernate JTA "
155+
+ "platform, are you using the correct "
156+
+ "version of Hibernate?", ex);
157+
}
158+
// Assume that Hibernate will use JNDI
159+
if (logger.isDebugEnabled()) {
160+
logger.debug("Unable to set Hibernate JTA platform : " + ex.getMessage());
161+
}
162+
}
163+
}
164+
165+
private boolean isUsingJndi() {
166+
try {
167+
return JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable();
168+
}
169+
catch (Error ex) {
170+
return false;
171+
}
172+
}
173+
174+
private Object getNoJtaPlatformManager() {
175+
return getJtaPlatformManager(NO_JTA_PLATFORM_CLASSES);
176+
}
177+
178+
private Object getJtaPlatformManager(String[] candidates) {
179+
for (String candidate : candidates) {
180+
try {
181+
return Class.forName(candidate).newInstance();
182+
}
183+
catch (Exception ex) {
184+
// Continue searching
185+
}
186+
}
187+
throw new IllegalStateException("Could not configure JTA platform");
188+
}
189+
190+
}

0 commit comments

Comments
 (0)