Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a28a2cd

Browse files
committed
Introduce JdbcConfiguration and extract factory methods used from AbstractJdbcConfiguration.
Closes: #2165 Original pull request: #2166
1 parent 888378b commit a28a2cd

File tree

9 files changed

+203
-92
lines changed

9 files changed

+203
-92
lines changed

‎spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java‎

Lines changed: 12 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -15,51 +15,37 @@
1515
*/
1616
package org.springframework.data.jdbc.repository.config;
1717

18-
import java.util.ArrayList;
1918
import java.util.Collection;
2019
import java.util.Collections;
2120
import java.util.HashSet;
2221
import java.util.List;
2322
import java.util.Optional;
2423
import java.util.Set;
2524

26-
import org.apache.commons.logging.Log;
27-
import org.apache.commons.logging.LogFactory;
2825
import org.springframework.beans.BeansException;
2926
import org.springframework.context.ApplicationContext;
3027
import org.springframework.context.ApplicationContextAware;
3128
import org.springframework.context.annotation.Bean;
3229
import org.springframework.context.annotation.Configuration;
3330
import org.springframework.context.annotation.Lazy;
3431
import org.springframework.core.convert.converter.Converter;
35-
import org.springframework.data.convert.CustomConversions;
3632
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
3733
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
3834
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
39-
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory;
40-
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
4135
import org.springframework.data.jdbc.core.convert.IdGeneratingEntityCallback;
4236
import org.springframework.data.jdbc.core.convert.JdbcConverter;
4337
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
44-
import org.springframework.data.jdbc.core.convert.MappingJdbcConverter;
4538
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
4639
import org.springframework.data.jdbc.core.convert.RelationResolver;
4740
import org.springframework.data.jdbc.core.dialect.DialectResolver;
48-
import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns;
4941
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
5042
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
51-
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
52-
import org.springframework.data.mapping.model.SimpleTypeHolder;
5343
import org.springframework.data.relational.RelationalManagedTypes;
5444
import org.springframework.data.relational.core.conversion.RelationalConverter;
5545
import org.springframework.data.relational.core.dialect.Dialect;
56-
import org.springframework.data.relational.core.mapping.DefaultNamingStrategy;
5746
import org.springframework.data.relational.core.mapping.NamingStrategy;
5847
import org.springframework.data.relational.core.mapping.Table;
59-
import org.springframework.data.util.TypeScanner;
60-
import org.springframework.jdbc.core.JdbcTemplate;
6148
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
62-
import org.springframework.util.StringUtils;
6349

6450
/**
6551
* Beans that must be registered for Spring Data JDBC to work.
@@ -77,8 +63,6 @@
7763
@Configuration(proxyBeanMethods = false)
7864
public class AbstractJdbcConfiguration implements ApplicationContextAware {
7965

80-
private static final Log LOG = LogFactory.getLog(AbstractJdbcConfiguration.class);
81-
8266
@SuppressWarnings("NullAway.Init") private ApplicationContext applicationContext;
8367

8468
private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY;
@@ -96,7 +80,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
9680
protected Collection<String> getMappingBasePackages() {
9781

9882
Package mappingBasePackage = getClass().getPackage();
99-
return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName());
83+
return mappingBasePackage == null ? List.of() : List.of(mappingBasePackage.getName());
10084
}
10185

10286
/**
@@ -124,13 +108,7 @@ public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException {
124108
@Bean
125109
public JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,
126110
JdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) {
127-
128-
JdbcMappingContext mappingContext = JdbcMappingContext
129-
.forQuotedIdentifiers(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE));
130-
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
131-
mappingContext.setManagedTypes(jdbcManagedTypes);
132-
133-
return mappingContext;
111+
return JdbcConfiguration.createMappingContext(jdbcManagedTypes, customConversions, namingStrategy.orElse(null));
134112
}
135113

136114
/**
@@ -143,7 +121,7 @@ public JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStra
143121
*/
144122
@Bean
145123
public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext,
146-
NamedParameterJdbcOperations operations, Dialect dialect) {
124+
NamedParameterJdbcOperations operations, JdbcDialect dialect) {
147125
return new IdGeneratingEntityCallback(mappingContext, dialect, operations);
148126
}
149127

@@ -157,57 +135,29 @@ public IdGeneratingEntityCallback idGeneratingBeforeSaveCallback(JdbcMappingCont
157135
*/
158136
@Bean
159137
public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations,
160-
@Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, Dialect dialect) {
161-
162-
JdbcArrayColumns arrayColumns = JdbcDialect.getArraySupport(dialect);
163-
DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns);
164-
165-
MappingJdbcConverter mappingJdbcConverter = new MappingJdbcConverter(mappingContext, relationResolver, conversions,
166-
jdbcTypeFactory);
167-
168-
if (operations.getJdbcOperations() instanceof JdbcTemplate jdbcTemplate) {
169-
mappingJdbcConverter.setExceptionTranslator(jdbcTemplate.getExceptionTranslator());
170-
}
171-
172-
return mappingJdbcConverter;
138+
@Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, JdbcDialect dialect) {
139+
return JdbcConfiguration.createConverter(mappingContext, operations, relationResolver, conversions, dialect);
173140
}
174141

175142
/**
176143
* Register custom {@link Converter}s in a {@link JdbcCustomConversions} object if required. These
177144
* {@link JdbcCustomConversions} will be registered with the
178-
* {@link #jdbcConverter(JdbcMappingContext, NamedParameterJdbcOperations, RelationResolver, JdbcCustomConversions, Dialect)}.
145+
* {@link #jdbcConverter(JdbcMappingContext, NamedParameterJdbcOperations, RelationResolver, JdbcCustomConversions, JdbcDialect)}.
179146
* Returns an empty {@link JdbcCustomConversions} instance by default.
180147
*
181148
* @return will never be {@literal null}.
182149
*/
183150
@Bean
184151
public JdbcCustomConversions jdbcCustomConversions() {
185152

186-
Dialect dialect = applicationContext.getBeanProvider(Dialect.class).getIfAvailable();
187-
188-
if (dialect == null) {
189-
LOG.warn("No JdbcDialect bean found; CustomConversions will be configured without dialect-specific types.");
190-
return new JdbcCustomConversions();
191-
}
192-
193-
SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER);
194-
195-
return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)),
196-
userConverters());
153+
JdbcDialect dialect = applicationContext.getBean(JdbcDialect.class);
154+
return JdbcConfiguration.createCustomConversions(dialect, userConverters());
197155
}
198156

199157
protected List<?> userConverters() {
200158
return Collections.emptyList();
201159
}
202160

203-
private List<Object> storeConverters(Dialect dialect) {
204-
205-
List<Object> converters = new ArrayList<>();
206-
converters.addAll(dialect.getConverters());
207-
converters.addAll(JdbcCustomConversions.storeConverters());
208-
return converters;
209-
}
210-
211161
/**
212162
* Register a {@link JdbcAggregateTemplate} as a bean for easy use in applications that need a lower level of
213163
* abstraction than the normal repository abstraction.
@@ -232,8 +182,8 @@ public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicatio
232182
*/
233183
@Bean
234184
public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter,
235-
JdbcMappingContext context, Dialect dialect) {
236-
return newDataAccessStrategyFactory(jdbcConverter, operations, dialect, this.queryMappingConfiguration).create();
185+
JdbcMappingContext context, JdbcDialect dialect) {
186+
return JdbcConfiguration.createDataAccessStrategy(operations, jdbcConverter, queryMappingConfiguration, dialect);
237187
}
238188

239189
/**
@@ -245,7 +195,7 @@ public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations op
245195
* @throws DialectResolver.NoDialectException if the {@link Dialect} cannot be determined.
246196
*/
247197
@Bean
248-
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
198+
public JdbcDialect jdbcDialect(NamedParameterJdbcOperations operations) {
249199
return DialectResolver.getDialect(operations.getJdbcOperations());
250200
}
251201

@@ -286,16 +236,7 @@ protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
286236
* @return a set of classes identified as entities.
287237
* @since 3.0
288238
*/
289-
@SuppressWarnings("unchecked")
290239
protected Set<Class<?>> scanForEntities(String basePackage) {
291-
292-
if (!StringUtils.hasText(basePackage)) {
293-
return Collections.emptySet();
294-
}
295-
296-
return TypeScanner.typeScanner(AbstractJdbcConfiguration.class.getClassLoader()) //
297-
.forTypesAnnotatedWith(Table.class) //
298-
.scanPackages(basePackage) //
299-
.collectAsSet();
240+
return JdbcConfiguration.scanForEntities(basePackage);
300241
}
301242
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright 2025 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+
* https://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+
package org.springframework.data.jdbc.repository.config;
17+
18+
import java.util.ArrayList;
19+
import java.util.Collections;
20+
import java.util.List;
21+
import java.util.Set;
22+
23+
import org.jspecify.annotations.Nullable;
24+
25+
import org.springframework.core.convert.converter.Converter;
26+
import org.springframework.data.convert.CustomConversions;
27+
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
28+
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
29+
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory;
30+
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory;
31+
import org.springframework.data.jdbc.core.convert.JdbcConverter;
32+
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
33+
import org.springframework.data.jdbc.core.convert.MappingJdbcConverter;
34+
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
35+
import org.springframework.data.jdbc.core.convert.RelationResolver;
36+
import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns;
37+
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
38+
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
39+
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
40+
import org.springframework.data.mapping.model.SimpleTypeHolder;
41+
import org.springframework.data.relational.RelationalManagedTypes;
42+
import org.springframework.data.relational.core.dialect.Dialect;
43+
import org.springframework.data.relational.core.mapping.DefaultNamingStrategy;
44+
import org.springframework.data.relational.core.mapping.NamingStrategy;
45+
import org.springframework.data.relational.core.mapping.Table;
46+
import org.springframework.data.util.TypeScanner;
47+
import org.springframework.jdbc.core.JdbcTemplate;
48+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
49+
import org.springframework.util.StringUtils;
50+
51+
/**
52+
* Utility class to providing factory methods for JDBC infrastructure components.
53+
* <p>
54+
* Mainly for use within the framework or for configuration arrangements that require customization of configuration.
55+
*
56+
* @author Mark Paluch
57+
* @since 4.0
58+
*/
59+
public final class JdbcConfiguration {
60+
61+
private JdbcConfiguration() {}
62+
63+
/**
64+
* Register custom {@link Converter}s in a {@link JdbcCustomConversions} object if required.
65+
*
66+
* @param dialect the JDBC dialect in use.
67+
* @param userConverters list of user converters, must not be {@literal null}.
68+
* @return will never be {@literal null}.
69+
*/
70+
public static JdbcCustomConversions createCustomConversions(JdbcDialect dialect, List<?> userConverters) {
71+
72+
SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER);
73+
74+
return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)),
75+
userConverters);
76+
}
77+
78+
private static List<Object> storeConverters(Dialect dialect) {
79+
80+
List<Object> converters = new ArrayList<>();
81+
converters.addAll(dialect.getConverters());
82+
converters.addAll(JdbcCustomConversions.storeConverters());
83+
return converters;
84+
}
85+
86+
/**
87+
* Register a {@link JdbcMappingContext} and apply an optional {@link NamingStrategy}.
88+
*
89+
* @param jdbcManagedTypes JDBC managed types.
90+
* @param customConversions the custom conversions.
91+
* @param namingStrategy optional {@link NamingStrategy}. Use {@link DefaultNamingStrategy#INSTANCE} as fallback.
92+
* @return must not be {@literal null}.
93+
*/
94+
public static JdbcMappingContext createMappingContext(RelationalManagedTypes jdbcManagedTypes,
95+
JdbcCustomConversions customConversions, @Nullable NamingStrategy namingStrategy) {
96+
97+
JdbcMappingContext mappingContext = JdbcMappingContext
98+
.forQuotedIdentifiers(namingStrategy != null ? namingStrategy : DefaultNamingStrategy.INSTANCE);
99+
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
100+
mappingContext.setManagedTypes(jdbcManagedTypes);
101+
102+
return mappingContext;
103+
}
104+
105+
/**
106+
* Creates a {@link JdbcConverter}.
107+
*
108+
* @param mappingContext must not be {@literal null}.
109+
* @param operations must not be {@literal null}.
110+
* @param relationResolver must not be {@literal null}.
111+
* @param conversions must not be {@literal null}.
112+
* @param dialect the JDBC dialect in use.
113+
* @return must not be {@literal null}.
114+
*/
115+
public static JdbcConverter createConverter(JdbcMappingContext mappingContext,
116+
NamedParameterJdbcOperations operations, RelationResolver relationResolver, JdbcCustomConversions conversions,
117+
JdbcDialect dialect) {
118+
119+
JdbcArrayColumns arrayColumns = JdbcDialect.getArraySupport(dialect);
120+
DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns);
121+
122+
MappingJdbcConverter mappingJdbcConverter = new MappingJdbcConverter(mappingContext, relationResolver, conversions,
123+
jdbcTypeFactory);
124+
125+
if (operations.getJdbcOperations() instanceof JdbcTemplate jdbcTemplate) {
126+
mappingJdbcConverter.setExceptionTranslator(jdbcTemplate.getExceptionTranslator());
127+
}
128+
129+
return mappingJdbcConverter;
130+
}
131+
132+
/**
133+
* Create a {@link DataAccessStrategy} for reuse in the {@link JdbcAggregateOperations} and the {@link JdbcConverter}.
134+
* Override this method to register a bean of type {@link DataAccessStrategy} if your use case requires a more
135+
* specialized {@link DataAccessStrategy}.
136+
*
137+
* @param operations must not be {@literal null}.
138+
* @param jdbcConverter must not be {@literal null}.
139+
* @param mappingConfiguration mapping configuration, can be {@literal null}.
140+
* @param dialect the JDBC dialect in use.
141+
* @return will never be {@literal null}.
142+
*/
143+
public static DataAccessStrategy createDataAccessStrategy(NamedParameterJdbcOperations operations,
144+
JdbcConverter jdbcConverter, @Nullable QueryMappingConfiguration mappingConfiguration, JdbcDialect dialect) {
145+
return new DataAccessStrategyFactory(jdbcConverter, operations, dialect,
146+
mappingConfiguration == null ? QueryMappingConfiguration.EMPTY : mappingConfiguration).create();
147+
}
148+
149+
/**
150+
* Scans the given base package for entities, i.e. JDBC-specific types annotated with {@link Table}.
151+
*
152+
* @param basePackage must not be {@literal null}.
153+
* @return a set of classes identified as entities.
154+
*/
155+
@SuppressWarnings("unchecked")
156+
public static Set<Class<?>> scanForEntities(String basePackage) {
157+
158+
if (!StringUtils.hasText(basePackage)) {
159+
return Collections.emptySet();
160+
}
161+
162+
return TypeScanner.typeScanner(JdbcConfiguration.class.getClassLoader()) //
163+
.forTypesAnnotatedWith(Table.class) //
164+
.scanPackages(basePackage) //
165+
.collectAsSet();
166+
}
167+
168+
}

‎spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/MyBatisJdbcConfiguration.java‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@
1818
import java.util.Optional;
1919

2020
import org.apache.ibatis.session.SqlSession;
21+
2122
import org.springframework.beans.factory.annotation.Autowired;
2223
import org.springframework.context.annotation.Bean;
2324
import org.springframework.context.annotation.Configuration;
2425
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
2526
import org.springframework.data.jdbc.core.convert.JdbcConverter;
2627
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
28+
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
2729
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
2830
import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy;
29-
import org.springframework.data.relational.core.dialect.Dialect;
3031
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3132

3233
/**
@@ -46,7 +47,7 @@ public class MyBatisJdbcConfiguration extends AbstractJdbcConfiguration {
4647
@Bean
4748
@Override
4849
public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations, JdbcConverter jdbcConverter,
49-
JdbcMappingContext context, Dialect dialect) {
50+
JdbcMappingContext context, JdbcDialect dialect) {
5051

5152
return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, jdbcConverter, operations, session, dialect,
5253
queryMappingConfiguration.orElse(QueryMappingConfiguration.EMPTY));

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /