Skip to content

Commit e122f06

Browse files
committed
Allow Data JDBC Dialect resolution without requiring DataSource init
1 parent c6c6ff0 commit e122f06

File tree

3 files changed

+67
-45
lines changed

3 files changed

+67
-45
lines changed

module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcDatabaseDialect.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.data.jdbc.autoconfigure;
1818

1919
import java.util.function.Function;
20+
import java.util.function.Supplier;
2021

2122
import org.springframework.data.jdbc.core.dialect.DialectResolver;
2223
import org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect;
@@ -81,11 +82,11 @@ public enum DataJdbcDatabaseDialect {
8182
*/
8283
SQL_SERVER(JdbcSqlServerDialect.INSTANCE);
8384

84-
private final Function<JdbcOperations, JdbcDialect> jdbcDialectResolver;
85+
private final Function<Supplier<JdbcOperations>, JdbcDialect> jdbcDialectResolver;
8586

8687
DataJdbcDatabaseDialect(Class<? extends JdbcDialect> jdbcDialectType) {
8788
this.jdbcDialectResolver = (jdbc) -> {
88-
JdbcDialect dialect = DialectResolver.getDialect(jdbc);
89+
JdbcDialect dialect = DialectResolver.getDialect(jdbc.get());
8990
Assert.isInstanceOf(jdbcDialectType, dialect);
9091
return dialect;
9192
};
@@ -95,7 +96,7 @@ public enum DataJdbcDatabaseDialect {
9596
this.jdbcDialectResolver = (jdbc) -> jdbcDialect;
9697
}
9798

98-
JdbcDialect getJdbcDialect(JdbcOperations jdbc) {
99+
JdbcDialect getJdbcDialect(Supplier<JdbcOperations> jdbc) {
99100
return this.jdbcDialectResolver.apply(jdbc);
100101
}
101102

module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesAutoConfiguration.java

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

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

19+
import java.util.Collections;
1920
import java.util.Optional;
20-
import java.util.Set;
2121

22+
import org.springframework.beans.factory.ObjectProvider;
2223
import org.springframework.boot.autoconfigure.AutoConfiguration;
2324
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2425
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -36,13 +37,17 @@
3637
import org.springframework.context.annotation.Lazy;
3738
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
3839
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
40+
import org.springframework.data.jdbc.core.convert.IdGeneratingEntityCallback;
3941
import org.springframework.data.jdbc.core.convert.JdbcConverter;
4042
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
43+
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
4144
import org.springframework.data.jdbc.core.convert.RelationResolver;
45+
import org.springframework.data.jdbc.core.dialect.DialectResolver;
4246
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
4347
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
4448
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
4549
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
50+
import org.springframework.data.jdbc.repository.config.JdbcConfiguration;
4651
import org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension;
4752
import org.springframework.data.relational.RelationalManagedTypes;
4853
import org.springframework.data.relational.core.mapping.NamingStrategy;
@@ -80,75 +85,65 @@ static class JdbcRepositoriesConfiguration {
8085

8186
@Configuration(proxyBeanMethods = false)
8287
@ConditionalOnMissingBean(AbstractJdbcConfiguration.class)
83-
static class SpringBootJdbcConfiguration extends AbstractJdbcConfiguration {
88+
static class SpringBootJdbcConfiguration {
8489

85-
private final ApplicationContext applicationContext;
86-
87-
private final DataJdbcProperties properties;
88-
89-
SpringBootJdbcConfiguration(ApplicationContext applicationContext, DataJdbcProperties properties) {
90-
this.applicationContext = applicationContext;
91-
this.properties = properties;
92-
}
93-
94-
@Override
95-
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
96-
return new EntityScanner(this.applicationContext).scan(Table.class);
90+
@Bean
91+
@ConditionalOnMissingBean
92+
RelationalManagedTypes jdbcManagedTypes(ApplicationContext applicationContext) throws ClassNotFoundException {
93+
return RelationalManagedTypes.fromIterable(new EntityScanner(applicationContext).scan(Table.class));
9794
}
9895

99-
@Override
10096
@Bean
10197
@ConditionalOnMissingBean
102-
public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException {
103-
return super.jdbcManagedTypes();
98+
JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,
99+
JdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) {
100+
return JdbcConfiguration.createMappingContext(jdbcManagedTypes, customConversions,
101+
namingStrategy.orElse(null));
104102
}
105103

106-
@Override
107104
@Bean
108105
@ConditionalOnMissingBean
109-
public JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,
110-
JdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) {
111-
return super.jdbcMappingContext(namingStrategy, customConversions, jdbcManagedTypes);
106+
IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext,
107+
NamedParameterJdbcOperations operations, JdbcDialect dialect) {
108+
return new IdGeneratingEntityCallback(mappingContext, dialect, operations);
112109
}
113110

114-
@Override
115111
@Bean
116112
@ConditionalOnMissingBean
117-
public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations,
113+
JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations,
118114
@Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, JdbcDialect dialect) {
119-
return super.jdbcConverter(mappingContext, operations, relationResolver, conversions, dialect);
115+
return JdbcConfiguration.createConverter(mappingContext, operations, relationResolver, conversions,
116+
dialect);
120117
}
121118

122-
@Override
123119
@Bean
124120
@ConditionalOnMissingBean
125-
public JdbcCustomConversions jdbcCustomConversions() {
126-
return super.jdbcCustomConversions();
121+
JdbcCustomConversions jdbcCustomConversions(JdbcDialect dialect) {
122+
return JdbcConfiguration.createCustomConversions(dialect, Collections.emptyList());
127123
}
128124

129-
@Override
130125
@Bean
131126
@ConditionalOnMissingBean
132-
public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext,
127+
JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext,
133128
JdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
134-
return super.jdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy);
129+
return new JdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy);
135130
}
136131

137-
@Override
138132
@Bean
139133
@ConditionalOnMissingBean
140-
public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations,
141-
JdbcConverter jdbcConverter, JdbcMappingContext context, JdbcDialect dialect) {
142-
return super.dataAccessStrategyBean(operations, jdbcConverter, context, dialect);
134+
DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter,
135+
JdbcMappingContext context, JdbcDialect dialect) {
136+
return JdbcConfiguration.createDataAccessStrategy(operations, jdbcConverter,
137+
QueryMappingConfiguration.EMPTY, dialect);
143138
}
144139

145-
@Override
146140
@Bean
147141
@ConditionalOnMissingBean
148-
public JdbcDialect jdbcDialect(NamedParameterJdbcOperations operations) {
149-
DataJdbcDatabaseDialect dialect = this.properties.getDialect();
150-
return (dialect != null) ? dialect.getJdbcDialect(operations.getJdbcOperations())
151-
: super.jdbcDialect(operations);
142+
JdbcDialect jdbcDialect(DataJdbcProperties properties,
143+
ObjectProvider<NamedParameterJdbcOperations> operations) {
144+
DataJdbcDatabaseDialect dialect = properties.getDialect();
145+
return (dialect != null) ? dialect.getJdbcDialect(() -> operations.getObject().getJdbcOperations())
146+
: DialectResolver.getDialect(operations.getObject().getJdbcOperations());
152147
}
153148

154149
}

module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesAutoConfigurationTests.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

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

19+
import java.lang.reflect.Method;
20+
import java.util.ArrayList;
21+
import java.util.List;
1922
import java.util.function.Function;
2023

2124
import javax.sql.DataSource;
@@ -25,6 +28,7 @@
2528

2629
import org.springframework.boot.autoconfigure.AutoConfigurations;
2730
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
31+
import org.springframework.boot.data.jdbc.autoconfigure.DataJdbcRepositoriesAutoConfiguration.SpringBootJdbcConfiguration;
2832
import org.springframework.boot.data.jdbc.domain.city.City;
2933
import org.springframework.boot.data.jdbc.domain.city.CityRepository;
3034
import org.springframework.boot.data.jdbc.domain.empty.EmptyDataPackage;
@@ -51,6 +55,7 @@
5155
import org.springframework.data.repository.Repository;
5256
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
5357
import org.springframework.test.util.ReflectionTestUtils;
58+
import org.springframework.util.ReflectionUtils;
5459

5560
import static org.assertj.core.api.Assertions.assertThat;
5661
import static org.mockito.Mockito.mock;
@@ -112,7 +117,7 @@ void basicAutoConfiguration() {
112117
DataSourceTransactionManagerAutoConfiguration.class))
113118
.withUserConfiguration(TestConfiguration.class)
114119
.run((context) -> {
115-
assertThat(context).hasSingleBean(AbstractJdbcConfiguration.class);
120+
assertThat(context).hasSingleBean(SpringBootJdbcConfiguration.class);
116121
assertThat(context).hasSingleBean(CityRepository.class);
117122
assertThat(context.getBean(CityRepository.class).findById(2000L)).isPresent();
118123
});
@@ -139,7 +144,7 @@ void autoConfigurationWithNoRepositories() {
139144
DataSourceTransactionManagerAutoConfiguration.class))
140145
.withUserConfiguration(EmptyConfiguration.class)
141146
.run((context) -> {
142-
assertThat(context).hasSingleBean(AbstractJdbcConfiguration.class);
147+
assertThat(context).hasSingleBean(SpringBootJdbcConfiguration.class);
143148
assertThat(context).doesNotHaveBean(Repository.class);
144149
});
145150
}
@@ -151,7 +156,7 @@ void honoursUsersEnableJdbcRepositoriesConfiguration() {
151156
DataSourceTransactionManagerAutoConfiguration.class))
152157
.withUserConfiguration(EnableRepositoriesConfiguration.class)
153158
.run((context) -> {
154-
assertThat(context).hasSingleBean(AbstractJdbcConfiguration.class);
159+
assertThat(context).hasSingleBean(SpringBootJdbcConfiguration.class);
155160
assertThat(context).hasSingleBean(CityRepository.class);
156161
assertThat(context.getBean(CityRepository.class).findById(2000L)).isPresent();
157162
});
@@ -207,6 +212,19 @@ void allowsConfigurationOfDialectByProperty() {
207212
.run((context) -> assertThat(context).hasSingleBean(JdbcPostgresDialect.class));
208213
}
209214

215+
@Test
216+
void springBootJdbcConfigurationDefinesTheSameBeansAsAbstractJdbcConfiguration() {
217+
assertThat(beanMethodsOf(SpringBootJdbcConfiguration.class))
218+
.containsExactlyInAnyOrderElementsOf(beanMethodsOf(AbstractJdbcConfiguration.class));
219+
}
220+
221+
private List<BeanMethod> beanMethodsOf(Class<?> source) {
222+
List<BeanMethod> beanMethods = new ArrayList<>();
223+
ReflectionUtils.doWithMethods(source, (method) -> beanMethods.add(BeanMethod.of(method)),
224+
(method) -> method.isAnnotationPresent(Bean.class));
225+
return beanMethods;
226+
}
227+
210228
private void allowsUserToDefineCustomBean(Class<?> configuration, Class<?> beanType, String beanName) {
211229
this.contextRunner.with(database())
212230
.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,
@@ -313,4 +331,12 @@ Dialect customDialect() {
313331

314332
}
315333

334+
record BeanMethod(String name, Class<?> returnType) {
335+
336+
static BeanMethod of(Method method) {
337+
return new BeanMethod(method.getName(), method.getReturnType());
338+
}
339+
340+
}
341+
316342
}

0 commit comments

Comments
 (0)