Skip to content

Commit 86ef089

Browse files
nosansnicoll
authored andcommitted
Use SQLExceptionTranslator bean if defined
This commit improves the auto-configuration of JdbcTemplate and HibernateJpaDialect so that an SQLExceptionTranslator bean is used if it is available. See gh-43511
1 parent 276b888 commit 86ef089

File tree

4 files changed

+62
-4
lines changed

4 files changed

+62
-4
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateConfiguration.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2024 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.
@@ -18,12 +18,14 @@
1818

1919
import javax.sql.DataSource;
2020

21+
import org.springframework.beans.factory.ObjectProvider;
2122
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2223
import org.springframework.context.annotation.Bean;
2324
import org.springframework.context.annotation.Configuration;
2425
import org.springframework.context.annotation.Primary;
2526
import org.springframework.jdbc.core.JdbcOperations;
2627
import org.springframework.jdbc.core.JdbcTemplate;
28+
import org.springframework.jdbc.support.SQLExceptionTranslator;
2729

2830
/**
2931
* Configuration for {@link JdbcTemplateConfiguration}.
@@ -36,14 +38,16 @@ class JdbcTemplateConfiguration {
3638

3739
@Bean
3840
@Primary
39-
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
41+
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties,
42+
ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator) {
4043
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
4144
JdbcProperties.Template template = properties.getTemplate();
4245
jdbcTemplate.setFetchSize(template.getFetchSize());
4346
jdbcTemplate.setMaxRows(template.getMaxRows());
4447
if (template.getQueryTimeout() != null) {
4548
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
4649
}
50+
sqlExceptionTranslator.ifUnique(jdbcTemplate::setExceptionTranslator);
4751
return jdbcTemplate;
4852
}
4953

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
5454
import org.springframework.context.annotation.Configuration;
5555
import org.springframework.context.annotation.ImportRuntimeHints;
56+
import org.springframework.jdbc.support.SQLExceptionTranslator;
5657
import org.springframework.jndi.JndiLocatorDelegate;
5758
import org.springframework.orm.hibernate5.SpringBeanContainer;
5859
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
@@ -95,6 +96,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
9596

9697
private final DataSourcePoolMetadataProvider poolMetadataProvider;
9798

99+
private final ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator;
100+
98101
private final List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers;
99102

100103
HibernateJpaConfiguration(DataSource dataSource, JpaProperties jpaProperties,
@@ -104,11 +107,13 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
104107
ObjectProvider<SchemaManagementProvider> providers,
105108
ObjectProvider<PhysicalNamingStrategy> physicalNamingStrategy,
106109
ObjectProvider<ImplicitNamingStrategy> implicitNamingStrategy,
110+
ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator,
107111
ObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) {
108112
super(dataSource, jpaProperties, jtaTransactionManager);
109113
this.hibernateProperties = hibernateProperties;
110114
this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(providers);
111115
this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider(metadataProviders.getIfAvailable());
116+
this.sqlExceptionTranslator = sqlExceptionTranslator;
112117
this.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers(
113118
physicalNamingStrategy.getIfAvailable(), implicitNamingStrategy.getIfAvailable(), beanFactory,
114119
hibernatePropertiesCustomizers.orderedStream().toList());
@@ -134,7 +139,9 @@ private List<HibernatePropertiesCustomizer> determineHibernatePropertiesCustomiz
134139

135140
@Override
136141
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
137-
return new HibernateJpaVendorAdapter();
142+
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
143+
this.sqlExceptionTranslator.ifUnique(adapter.getJpaDialect()::setJdbcExceptionTranslator);
144+
return adapter;
138145
}
139146

140147
@Override

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JdbcTemplateAutoConfigurationTests.java

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 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,8 @@
3434
import org.springframework.jdbc.core.JdbcTemplate;
3535
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3636
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
37+
import org.springframework.jdbc.support.SQLExceptionTranslator;
38+
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
3739

3840
import static org.assertj.core.api.Assertions.assertThat;
3941
import static org.mockito.Mockito.mock;
@@ -204,6 +206,31 @@ void testDependencyToLiquibaseWithJdbcTemplateMixed() {
204206
});
205207
}
206208

209+
@Test
210+
void shouldConfigureJdbcTemplateWithSQLExceptionTranslatorIfPresent() {
211+
SQLStateSQLExceptionTranslator sqlExceptionTranslator = new SQLStateSQLExceptionTranslator();
212+
this.contextRunner.withBean(SQLExceptionTranslator.class, () -> sqlExceptionTranslator).run((context) -> {
213+
assertThat(context).hasSingleBean(JdbcTemplate.class);
214+
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
215+
assertThat(jdbcTemplate.getExceptionTranslator()).isSameAs(sqlExceptionTranslator);
216+
});
217+
}
218+
219+
@Test
220+
void shouldNotConfigureJdbcTemplateWithSQLExceptionTranslatorIfNotUnique() {
221+
SQLStateSQLExceptionTranslator sqlExceptionTranslator1 = new SQLStateSQLExceptionTranslator();
222+
SQLStateSQLExceptionTranslator sqlExceptionTranslator2 = new SQLStateSQLExceptionTranslator();
223+
this.contextRunner
224+
.withBean("sqlExceptionTranslator1", SQLExceptionTranslator.class, () -> sqlExceptionTranslator1)
225+
.withBean("sqlExceptionTranslator2", SQLExceptionTranslator.class, () -> sqlExceptionTranslator2)
226+
.run((context) -> {
227+
assertThat(context).hasSingleBean(JdbcTemplate.class);
228+
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
229+
assertThat(jdbcTemplate.getExceptionTranslator()).isNotSameAs(sqlExceptionTranslator1)
230+
.isNotSameAs(sqlExceptionTranslator2);
231+
});
232+
}
233+
207234
@Configuration(proxyBeanMethods = false)
208235
static class CustomConfiguration {
209236

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@
7878
import org.springframework.context.annotation.Configuration;
7979
import org.springframework.context.event.ContextRefreshedEvent;
8080
import org.springframework.jdbc.core.JdbcTemplate;
81+
import org.springframework.jdbc.support.SQLExceptionTranslator;
82+
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
8183
import org.springframework.orm.jpa.JpaTransactionManager;
8284
import org.springframework.orm.jpa.JpaVendorAdapter;
8385
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -169,6 +171,24 @@ void hibernateDialectIsNotSetByDefault() {
169171
(adapter) -> assertThat(adapter.getJpaPropertyMap()).doesNotContainKeys("hibernate.dialect")));
170172
}
171173

174+
@Test
175+
void shouldConfigureHibernateJpaDialectWithSqlExceptionTranslatorIfPresent() {
176+
SQLStateSQLExceptionTranslator sqlExceptionTranslator = new SQLStateSQLExceptionTranslator();
177+
contextRunner().withBean(SQLStateSQLExceptionTranslator.class, () -> sqlExceptionTranslator)
178+
.run(assertJpaVendorAdapter((adapter) -> assertThat(adapter.getJpaDialect())
179+
.hasFieldOrPropertyWithValue("jdbcExceptionTranslator", sqlExceptionTranslator)));
180+
}
181+
182+
@Test
183+
void shouldNotConfigureHibernateJpaDialectWithSqlExceptionTranslatorIfNotUnique() {
184+
SQLStateSQLExceptionTranslator sqlExceptionTranslator1 = new SQLStateSQLExceptionTranslator();
185+
SQLStateSQLExceptionTranslator sqlExceptionTranslator2 = new SQLStateSQLExceptionTranslator();
186+
contextRunner().withBean("sqlExceptionTranslator1", SQLExceptionTranslator.class, () -> sqlExceptionTranslator1)
187+
.withBean("sqlExceptionTranslator2", SQLExceptionTranslator.class, () -> sqlExceptionTranslator2)
188+
.run(assertJpaVendorAdapter((adapter) -> assertThat(adapter.getJpaDialect())
189+
.hasFieldOrPropertyWithValue("jdbcExceptionTranslator", null)));
190+
}
191+
172192
@Test
173193
void hibernateDialectIsSetWhenDatabaseIsSet() {
174194
contextRunner().withPropertyValues("spring.jpa.database=H2")

0 commit comments

Comments
 (0)