Skip to content

Commit

Permalink
Use SQLExceptionTranslator bean if defined
Browse files Browse the repository at this point in the history
Auto-configure JdbcTemplate and HibernateJpaDialect beans
with SQLExceptionTranslator bean if the latter one is unique

See gh-43485
  • Loading branch information
nosan committed Dec 15, 2024
1 parent bb6c50b commit bddd1ea
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2024 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.
Expand All @@ -18,12 +18,14 @@

import javax.sql.DataSource;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.SQLExceptionTranslator;

/**
* Configuration for {@link JdbcTemplateConfiguration}.
Expand All @@ -36,14 +38,16 @@ class JdbcTemplateConfiguration {

@Bean
@Primary
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties,
ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
}
sqlExceptionTranslator.ifUnique(jdbcTemplate::setExceptionTranslator);
return jdbcTemplate;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jndi.JndiLocatorDelegate;
import org.springframework.orm.hibernate5.SpringBeanContainer;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
Expand Down Expand Up @@ -95,6 +96,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {

private final DataSourcePoolMetadataProvider poolMetadataProvider;

private final ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator;

private final List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers;

HibernateJpaConfiguration(DataSource dataSource, JpaProperties jpaProperties,
Expand All @@ -104,11 +107,13 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration {
ObjectProvider<SchemaManagementProvider> providers,
ObjectProvider<PhysicalNamingStrategy> physicalNamingStrategy,
ObjectProvider<ImplicitNamingStrategy> implicitNamingStrategy,
ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator,
ObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) {
super(dataSource, jpaProperties, jtaTransactionManager);
this.hibernateProperties = hibernateProperties;
this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(providers);
this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider(metadataProviders.getIfAvailable());
this.sqlExceptionTranslator = sqlExceptionTranslator;
this.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers(
physicalNamingStrategy.getIfAvailable(), implicitNamingStrategy.getIfAvailable(), beanFactory,
hibernatePropertiesCustomizers.orderedStream().toList());
Expand All @@ -134,7 +139,9 @@ private List<HibernatePropertiesCustomizer> determineHibernatePropertiesCustomiz

@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
this.sqlExceptionTranslator.ifUnique(adapter.getJpaDialect()::setJdbcExceptionTranslator);
return adapter;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
Expand Down Expand Up @@ -34,6 +34,8 @@
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -204,6 +206,31 @@ void testDependencyToLiquibaseWithJdbcTemplateMixed() {
});
}

@Test
void shouldConfigureJdbcTemplateWithSQLExceptionTranslatorIfPresent() {
SQLStateSQLExceptionTranslator sqlExceptionTranslator = new SQLStateSQLExceptionTranslator();
this.contextRunner.withBean(SQLExceptionTranslator.class, () -> sqlExceptionTranslator).run((context) -> {
assertThat(context).hasSingleBean(JdbcTemplate.class);
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
assertThat(jdbcTemplate.getExceptionTranslator()).isSameAs(sqlExceptionTranslator);
});
}

@Test
void shouldNotConfigureJdbcTemplateWithSQLExceptionTranslatorIfNotUnique() {
SQLStateSQLExceptionTranslator sqlExceptionTranslator1 = new SQLStateSQLExceptionTranslator();
SQLStateSQLExceptionTranslator sqlExceptionTranslator2 = new SQLStateSQLExceptionTranslator();
this.contextRunner
.withBean("sqlExceptionTranslator1", SQLExceptionTranslator.class, () -> sqlExceptionTranslator1)
.withBean("sqlExceptionTranslator2", SQLExceptionTranslator.class, () -> sqlExceptionTranslator2)
.run((context) -> {
assertThat(context).hasSingleBean(JdbcTemplate.class);
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
assertThat(jdbcTemplate.getExceptionTranslator()).isNotSameAs(sqlExceptionTranslator1)
.isNotSameAs(sqlExceptionTranslator2);
});
}

@Configuration(proxyBeanMethods = false)
static class CustomConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
Expand Down Expand Up @@ -169,6 +171,24 @@ void hibernateDialectIsNotSetByDefault() {
(adapter) -> assertThat(adapter.getJpaPropertyMap()).doesNotContainKeys("hibernate.dialect")));
}

@Test
void shouldConfigureHibernateJpaDialectWithSqlExceptionTranslatorIfPresent() {
SQLStateSQLExceptionTranslator sqlExceptionTranslator = new SQLStateSQLExceptionTranslator();
contextRunner().withBean(SQLStateSQLExceptionTranslator.class, () -> sqlExceptionTranslator)
.run(assertJpaVendorAdapter((adapter) -> assertThat(adapter.getJpaDialect())
.hasFieldOrPropertyWithValue("jdbcExceptionTranslator", sqlExceptionTranslator)));
}

@Test
void shouldNotConfigureHibernateJpaDialectWithSqlExceptionTranslatorIfNotUnique() {
SQLStateSQLExceptionTranslator sqlExceptionTranslator1 = new SQLStateSQLExceptionTranslator();
SQLStateSQLExceptionTranslator sqlExceptionTranslator2 = new SQLStateSQLExceptionTranslator();
contextRunner().withBean("sqlExceptionTranslator1", SQLExceptionTranslator.class, () -> sqlExceptionTranslator1)
.withBean("sqlExceptionTranslator2", SQLExceptionTranslator.class, () -> sqlExceptionTranslator2)
.run(assertJpaVendorAdapter((adapter) -> assertThat(adapter.getJpaDialect())
.hasFieldOrPropertyWithValue("jdbcExceptionTranslator", null)));
}

@Test
void hibernateDialectIsSetWhenDatabaseIsSet() {
contextRunner().withPropertyValues("spring.jpa.database=H2")
Expand Down

0 comments on commit bddd1ea

Please sign in to comment.