Skip to content

Commit 0ae7e93

Browse files
committed
Allow user to replace auto-configured Data JDBC beans
Closes gh-32571
1 parent 7c4e46e commit 0ae7e93

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

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

+65
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.data.jdbc;
1818

19+
import java.util.Optional;
1920
import java.util.Set;
2021

2122
import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -28,11 +29,22 @@
2829
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
2930
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
3031
import org.springframework.context.ApplicationContext;
32+
import org.springframework.context.annotation.Bean;
3133
import org.springframework.context.annotation.Configuration;
3234
import org.springframework.context.annotation.Import;
35+
import org.springframework.context.annotation.Lazy;
36+
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
37+
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
38+
import org.springframework.data.jdbc.core.convert.JdbcConverter;
39+
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
40+
import org.springframework.data.jdbc.core.convert.RelationResolver;
41+
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
3342
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
3443
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
3544
import org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension;
45+
import org.springframework.data.relational.RelationalManagedTypes;
46+
import org.springframework.data.relational.core.dialect.Dialect;
47+
import org.springframework.data.relational.core.mapping.NamingStrategy;
3648
import org.springframework.data.relational.core.mapping.Table;
3749
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3850
import org.springframework.transaction.PlatformTransactionManager;
@@ -79,6 +91,59 @@ protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
7991
return new EntityScanner(this.applicationContext).scan(Table.class);
8092
}
8193

94+
@Override
95+
@Bean
96+
@ConditionalOnMissingBean
97+
public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException {
98+
return super.jdbcManagedTypes();
99+
}
100+
101+
@Override
102+
@Bean
103+
@ConditionalOnMissingBean
104+
public JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,
105+
JdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) {
106+
return super.jdbcMappingContext(namingStrategy, customConversions, jdbcManagedTypes);
107+
}
108+
109+
@Override
110+
@Bean
111+
@ConditionalOnMissingBean
112+
public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations,
113+
@Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, Dialect dialect) {
114+
return super.jdbcConverter(mappingContext, operations, relationResolver, conversions, dialect);
115+
}
116+
117+
@Override
118+
@Bean
119+
@ConditionalOnMissingBean
120+
public JdbcCustomConversions jdbcCustomConversions() {
121+
return super.jdbcCustomConversions();
122+
}
123+
124+
@Override
125+
@Bean
126+
@ConditionalOnMissingBean
127+
public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext,
128+
JdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
129+
return super.jdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy);
130+
}
131+
132+
@Override
133+
@Bean
134+
@ConditionalOnMissingBean
135+
public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations,
136+
JdbcConverter jdbcConverter, JdbcMappingContext context, Dialect dialect) {
137+
return super.dataAccessStrategyBean(operations, jdbcConverter, context, dialect);
138+
}
139+
140+
@Override
141+
@Bean
142+
@ConditionalOnMissingBean
143+
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
144+
return super.jdbcDialect(operations);
145+
}
146+
82147
}
83148

84149
}

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

+129
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import javax.sql.DataSource;
2222

2323
import org.junit.jupiter.api.Test;
24+
import org.mockito.Answers;
2425

2526
import org.springframework.boot.autoconfigure.AutoConfigurations;
2627
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
@@ -32,16 +33,24 @@
3233
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
3334
import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration;
3435
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
36+
import org.springframework.context.annotation.Bean;
3537
import org.springframework.context.annotation.Configuration;
3638
import org.springframework.data.domain.ManagedTypes;
39+
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
40+
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
41+
import org.springframework.data.jdbc.core.convert.JdbcConverter;
42+
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
3743
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
3844
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
3945
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
46+
import org.springframework.data.relational.RelationalManagedTypes;
47+
import org.springframework.data.relational.core.dialect.Dialect;
4048
import org.springframework.data.repository.Repository;
4149
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
4250
import org.springframework.test.util.ReflectionTestUtils;
4351

4452
import static org.assertj.core.api.Assertions.assertThat;
53+
import static org.mockito.Mockito.mock;
4554

4655
/**
4756
* Tests for {@link JdbcRepositoriesAutoConfiguration}.
@@ -128,6 +137,56 @@ void honoursUsersEnableJdbcRepositoriesConfiguration() {
128137
});
129138
}
130139

140+
@Test
141+
void allowsUserToDefineCustomRelationalManagedTypes() {
142+
allowsUserToDefineCustomBean(RelationalManagedTypesConfiguration.class, RelationalManagedTypes.class,
143+
"customRelationalManagedTypes");
144+
}
145+
146+
@Test
147+
void allowsUserToDefineCustomJdbcMappingContext() {
148+
allowsUserToDefineCustomBean(JdbcMappingContextConfiguration.class, JdbcMappingContext.class,
149+
"customJdbcMappingContext");
150+
}
151+
152+
@Test
153+
void allowsUserToDefineCustomJdbcConverter() {
154+
allowsUserToDefineCustomBean(JdbcConverterConfiguration.class, JdbcConverter.class, "customJdbcConverter");
155+
}
156+
157+
@Test
158+
void allowsUserToDefineCustomJdbcCustomConversions() {
159+
allowsUserToDefineCustomBean(JdbcCustomConversionsConfiguration.class, JdbcCustomConversions.class,
160+
"customJdbcCustomConversions");
161+
}
162+
163+
@Test
164+
void allowsUserToDefineCustomJdbcAggregateTemplate() {
165+
allowsUserToDefineCustomBean(JdbcAggregateTemplateConfiguration.class, JdbcAggregateTemplate.class,
166+
"customJdbcAggregateTemplate");
167+
}
168+
169+
@Test
170+
void allowsUserToDefineCustomDataAccessStrategy() {
171+
allowsUserToDefineCustomBean(DataAccessStrategyConfiguration.class, DataAccessStrategy.class,
172+
"customDataAccessStrategy");
173+
}
174+
175+
@Test
176+
void allowsUserToDefineCustomDialect() {
177+
allowsUserToDefineCustomBean(DialectConfiguration.class, Dialect.class, "customDialect");
178+
}
179+
180+
private void allowsUserToDefineCustomBean(Class<?> configuration, Class<?> beanType, String beanName) {
181+
this.contextRunner.with(database())
182+
.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,
183+
DataSourceTransactionManagerAutoConfiguration.class))
184+
.withUserConfiguration(configuration, EmptyConfiguration.class).run((context) -> {
185+
assertThat(context).hasSingleBean(beanType);
186+
assertThat(context).hasBean(beanName);
187+
});
188+
}
189+
131190
private Function<ApplicationContextRunner, ApplicationContextRunner> database() {
132191
return (runner) -> runner
133192
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
@@ -154,4 +213,74 @@ static class EnableRepositoriesConfiguration {
154213

155214
}
156215

216+
@Configuration(proxyBeanMethods = false)
217+
static class RelationalManagedTypesConfiguration {
218+
219+
@Bean
220+
RelationalManagedTypes customRelationalManagedTypes() {
221+
return RelationalManagedTypes.empty();
222+
}
223+
224+
}
225+
226+
@Configuration(proxyBeanMethods = false)
227+
static class JdbcMappingContextConfiguration {
228+
229+
@Bean
230+
JdbcMappingContext customJdbcMappingContext() {
231+
return mock(JdbcMappingContext.class);
232+
}
233+
234+
}
235+
236+
@Configuration(proxyBeanMethods = false)
237+
static class JdbcConverterConfiguration {
238+
239+
@Bean
240+
JdbcConverter customJdbcConverter() {
241+
return mock(JdbcConverter.class);
242+
}
243+
244+
}
245+
246+
@Configuration(proxyBeanMethods = false)
247+
static class JdbcCustomConversionsConfiguration {
248+
249+
@Bean
250+
JdbcCustomConversions customJdbcCustomConversions() {
251+
return mock(JdbcCustomConversions.class, Answers.RETURNS_MOCKS);
252+
}
253+
254+
}
255+
256+
@Configuration(proxyBeanMethods = false)
257+
static class JdbcAggregateTemplateConfiguration {
258+
259+
@Bean
260+
JdbcAggregateTemplate customJdbcAggregateTemplate() {
261+
return mock(JdbcAggregateTemplate.class);
262+
}
263+
264+
}
265+
266+
@Configuration(proxyBeanMethods = false)
267+
static class DataAccessStrategyConfiguration {
268+
269+
@Bean
270+
DataAccessStrategy customDataAccessStrategy() {
271+
return mock(DataAccessStrategy.class);
272+
}
273+
274+
}
275+
276+
@Configuration(proxyBeanMethods = false)
277+
static class DialectConfiguration {
278+
279+
@Bean
280+
Dialect customDialect() {
281+
return mock(Dialect.class, Answers.RETURNS_MOCKS);
282+
}
283+
284+
}
285+
157286
}

0 commit comments

Comments
 (0)