Skip to content

Commit e3a70e7

Browse files
committed
GH-2020 Added SqlTypeResolver abstraction
Signed-off-by: mipo256 <[email protected]>
1 parent e82befd commit e3a70e7

File tree

20 files changed

+665
-99
lines changed

20 files changed

+665
-99
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultJdbcTypeFactory.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,6 @@ public DefaultJdbcTypeFactory(JdbcOperations operations) {
4444
this(operations, org.springframework.data.jdbc.core.dialect.JdbcArrayColumns.DefaultSupport.INSTANCE);
4545
}
4646

47-
/**
48-
* Creates a new {@link DefaultJdbcTypeFactory}.
49-
*
50-
* @param operations must not be {@literal null}.
51-
* @since 2.3
52-
* @deprecated use
53-
* {@link #DefaultJdbcTypeFactory(JdbcOperations, org.springframework.data.jdbc.core.dialect.JdbcArrayColumns)}
54-
* instead.
55-
*/
56-
@Deprecated(forRemoval = true, since = "3.5")
57-
public DefaultJdbcTypeFactory(JdbcOperations operations, JdbcArrayColumns arrayColumns) {
58-
59-
Assert.notNull(operations, "JdbcOperations must not be null");
60-
Assert.notNull(arrayColumns, "JdbcArrayColumns must not be null");
61-
62-
this.operations = operations;
63-
this.arrayColumns = arrayColumns;
64-
}
65-
6647
/**
6748
* Creates a new {@link DefaultJdbcTypeFactory}.
6849
*

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DelegatingDataAccessStrategy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ public class DelegatingDataAccessStrategy implements DataAccessStrategy {
4545

4646
private DataAccessStrategy delegate;
4747

48+
/**
49+
* @deprecated please, use {@link DelegatingDataAccessStrategy#DelegatingDataAccessStrategy(DataAccessStrategy)} instead
50+
*/
51+
@Deprecated(forRemoval = true, since = "4.0")
4852
public DelegatingDataAccessStrategy() {}
4953

5054
public DelegatingDataAccessStrategy(DataAccessStrategy delegate) {

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/dialect/JdbcDialect.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package org.springframework.data.jdbc.core.dialect;
1717

1818
import org.springframework.data.relational.core.dialect.Dialect;
19+
import org.springframework.data.jdbc.core.dialect.SqlTypeResolver;
20+
import org.springframework.data.jdbc.core.dialect.DefaultSqlTypeResolver;
1921

2022
/**
2123
* {@link org.springframework.data.relational.core.dialect.ArrayColumns} that offer JDBC specific functionality.
@@ -37,4 +39,12 @@ default JdbcArrayColumns getArraySupport() {
3739
return JdbcArrayColumns.Unsupported.INSTANCE;
3840
}
3941

42+
/**
43+
* Returns a {@link SqlTypeResolver} of this dialect.
44+
*
45+
* @since 4.0
46+
*/
47+
default SqlTypeResolver getSqlTypeResolver() {
48+
return DefaultSqlTypeResolver.INSTANCE;
49+
}
4050
}

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcParameters.java

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,47 @@
2121
import org.springframework.core.MethodParameter;
2222
import org.springframework.data.jdbc.core.convert.JdbcColumnTypes;
2323
import org.springframework.data.jdbc.support.JdbcUtil;
24+
import org.springframework.data.jdbc.core.dialect.DefaultSqlTypeResolver;
25+
import org.springframework.data.jdbc.core.dialect.SqlTypeResolver;
2426
import org.springframework.data.relational.repository.query.RelationalParameters;
2527
import org.springframework.data.repository.query.Parameter;
2628
import org.springframework.data.repository.query.ParametersSource;
2729
import org.springframework.data.util.Lazy;
2830
import org.springframework.data.util.TypeInformation;
31+
import org.springframework.util.Assert;
2932

3033
/**
3134
* Custom extension of {@link RelationalParameters}.
3235
*
3336
* @author Mark Paluch
37+
* @author Mikhail Polivakha
3438
* @since 3.2.6
3539
*/
3640
public class JdbcParameters extends RelationalParameters {
3741

3842
/**
39-
* Creates a new {@link JdbcParameters} instance from the given {@link ParametersSource}.
43+
* Creates a new {@link JdbcParameters} instance from the given {@link ParametersSource}. Uses the {@link DefaultSqlTypeResolver}.
4044
*
4145
* @param parametersSource must not be {@literal null}.
4246
*/
4347
public JdbcParameters(ParametersSource parametersSource) {
4448
super(parametersSource,
45-
methodParameter -> new JdbcParameter(methodParameter, parametersSource.getDomainTypeInformation()));
49+
methodParameter -> new JdbcParameter(methodParameter, parametersSource.getDomainTypeInformation(),
50+
DefaultSqlTypeResolver.INSTANCE));
51+
}
52+
53+
/**
54+
* Creates a new {@link JdbcParameters} instance from the given {@link ParametersSource} and given {@link SqlTypeResolver}.
55+
*
56+
* @param parametersSource must not be {@literal null}.
57+
* @param sqlTypeResolver must not be {@literal null}.
58+
*/
59+
public JdbcParameters(ParametersSource parametersSource, SqlTypeResolver sqlTypeResolver) {
60+
super(parametersSource,
61+
methodParameter -> new JdbcParameter(methodParameter, parametersSource.getDomainTypeInformation(), sqlTypeResolver));
62+
63+
Assert.notNull(sqlTypeResolver, "SqlTypeResolver must not be null");
64+
Assert.notNull(parametersSource, "ParametersSource must not be null");
4665
}
4766

4867
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -69,27 +88,42 @@ protected JdbcParameters createFrom(List<RelationalParameter> parameters) {
6988
*/
7089
public static class JdbcParameter extends RelationalParameter {
7190

72-
private final SQLType sqlType;
91+
private final Lazy<SQLType> sqlType;
7392
private final Lazy<SQLType> actualSqlType;
7493

7594
/**
7695
* Creates a new {@link RelationalParameter}.
7796
*
7897
* @param parameter must not be {@literal null}.
7998
*/
80-
JdbcParameter(MethodParameter parameter, TypeInformation<?> domainType) {
99+
JdbcParameter(MethodParameter parameter, TypeInformation<?> domainType, SqlTypeResolver sqlTypeResolver) {
81100
super(parameter, domainType);
82101

83102
TypeInformation<?> typeInformation = getTypeInformation();
84103

85-
sqlType = JdbcUtil.targetSqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(typeInformation.getType()));
104+
sqlType = Lazy.of(() -> {
105+
SQLType resolvedSqlType = sqlTypeResolver.resolveSqlType(this);
106+
107+
if (resolvedSqlType == null) {
108+
return JdbcUtil.targetSqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(typeInformation.getType()));
109+
} else {
110+
return resolvedSqlType;
111+
}
112+
});
113+
114+
actualSqlType = Lazy.of(() -> {
115+
SQLType resolvedActualSqlType = sqlTypeResolver.resolveActualSqlType(this);
86116

87-
actualSqlType = Lazy.of(() -> JdbcUtil
88-
.targetSqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(typeInformation.getActualType().getType())));
117+
if (resolvedActualSqlType == null) {
118+
return JdbcUtil.targetSqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(typeInformation.getActualType().getType()));
119+
} else {
120+
return resolvedActualSqlType;
121+
}
122+
});
89123
}
90124

91125
public SQLType getSqlType() {
92-
return sqlType;
126+
return sqlType.get();
93127
}
94128

95129
public SQLType getActualSqlType() {

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryMethod.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.springframework.core.annotation.AnnotationUtils;
2525
import org.springframework.data.mapping.context.MappingContext;
2626
import org.springframework.data.projection.ProjectionFactory;
27+
import org.springframework.data.jdbc.core.dialect.DefaultSqlTypeResolver;
28+
import org.springframework.data.jdbc.core.dialect.SqlTypeResolver;
2729
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2830
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2931
import org.springframework.data.relational.repository.Lock;
@@ -34,6 +36,7 @@
3436
import org.springframework.data.repository.query.Parameters;
3537
import org.springframework.data.repository.query.ParametersSource;
3638
import org.springframework.data.repository.query.QueryMethod;
39+
import org.springframework.data.util.Lazy;
3740
import org.springframework.jdbc.core.ResultSetExtractor;
3841
import org.springframework.jdbc.core.RowMapper;
3942
import org.springframework.lang.Nullable;
@@ -53,6 +56,7 @@
5356
* @author Diego Krupitza
5457
* @author Mark Paluch
5558
* @author Daeho Kwon
59+
* @author Mikhail Polivakha
5660
*/
5761
public class JdbcQueryMethod extends QueryMethod {
5862

@@ -67,8 +71,15 @@ public class JdbcQueryMethod extends QueryMethod {
6771
public JdbcQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
6872
NamedQueries namedQueries,
6973
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext) {
74+
this(method, metadata, factory, namedQueries, mappingContext, DefaultSqlTypeResolver.INSTANCE);
75+
}
76+
77+
public JdbcQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
78+
NamedQueries namedQueries,
79+
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext,
80+
SqlTypeResolver sqlTypeResolver) {
7081

71-
super(method, metadata, factory, JdbcParameters::new);
82+
super(method, metadata, factory, parametersSource -> new JdbcParameters(parametersSource, sqlTypeResolver));
7283
this.namedQueries = namedQueries;
7384
this.method = method;
7485
this.mappingContext = mappingContext;

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
8585

8686
/**
8787
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
88-
* and {@link org.springframework.data.jdbc.repository.query.RowMapperFactory}.
88+
* and {@link RowMapperFactory}.
8989
*
90-
* @param queryMethod must not be {@literal null}.
91-
* @param operations must not be {@literal null}.
90+
* @param queryMethod must not be {@literal null}.
91+
* @param operations must not be {@literal null}.
9292
* @param rowMapperFactory must not be {@literal null}.
93-
* @param converter must not be {@literal null}.
94-
* @param delegate must not be {@literal null}.
93+
* @param converter must not be {@literal null}.
94+
* @param delegate must not be {@literal null}.
9595
* @since 3.4
9696
*/
9797
public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
@@ -104,12 +104,12 @@ public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOpera
104104
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
105105
* and {@link org.springframework.data.jdbc.repository.query.RowMapperFactory}.
106106
*
107-
* @param query must not be {@literal null} or empty.
108-
* @param queryMethod must not be {@literal null}.
109-
* @param operations must not be {@literal null}.
107+
* @param query must not be {@literal null} or empty.
108+
* @param queryMethod must not be {@literal null}.
109+
* @param operations must not be {@literal null}.
110110
* @param rowMapperFactory must not be {@literal null}.
111-
* @param converter must not be {@literal null}.
112-
* @param delegate must not be {@literal null}.
111+
* @param converter must not be {@literal null}.
112+
* @param delegate must not be {@literal null}.
113113
* @since 3.4
114114
*/
115115
public StringBasedJdbcQuery(String query, JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
@@ -347,7 +347,8 @@ private static boolean isUnconfigured(@Nullable Class<?> configuredClass, Class<
347347
}
348348

349349
@Deprecated(since = "3.4")
350-
public void setBeanFactory(BeanFactory beanFactory) {}
350+
public void setBeanFactory(BeanFactory beanFactory) {
351+
}
351352

352353
class CachedRowMapperFactory {
353354

@@ -406,19 +407,20 @@ public CachedResultSetExtractorFactory(Supplier<RowMapper<?>> resultSetExtractor
406407
String resultSetExtractorRef = getQueryMethod().getResultSetExtractorRef();
407408
Class<? extends ResultSetExtractor> resultSetExtractorClass = getQueryMethod().getResultSetExtractorClass();
408409

409-
if (!ObjectUtils.isEmpty(resultSetExtractorRef)
410-
&& !isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class)) {
410+
if (!ObjectUtils.isEmpty(resultSetExtractorRef) && !isUnconfigured(resultSetExtractorClass,
411+
ResultSetExtractor.class)) {
411412
throw new IllegalArgumentException(
412413
"Invalid ResultSetExtractor configuration. Configure either one but not both via @Query(resultSetExtractorRef = …, resultSetExtractorClass = …) for query method "
413414
+ getQueryMethod());
414415
}
415416

416-
this.configuredResultSetExtractor = !ObjectUtils.isEmpty(resultSetExtractorRef)
417-
|| !isUnconfigured(resultSetExtractorClass, ResultSetExtractor.class);
417+
this.configuredResultSetExtractor =
418+
!ObjectUtils.isEmpty(resultSetExtractorRef) || !isUnconfigured(resultSetExtractorClass,
419+
ResultSetExtractor.class);
418420

419-
this.rowMapperConstructor = resultSetExtractorClass != null
420-
? ClassUtils.getConstructorIfAvailable(resultSetExtractorClass, RowMapper.class)
421-
: null;
421+
this.rowMapperConstructor = resultSetExtractorClass != null ?
422+
ClassUtils.getConstructorIfAvailable(resultSetExtractorClass, RowMapper.class) :
423+
null;
422424
this.constructor = resultSetExtractorClass != null ? findPrimaryConstructor(resultSetExtractorClass) : null;
423425
this.resultSetExtractorFactory = rowMapper -> {
424426

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.context.ApplicationEventPublisher;
2424
import org.springframework.data.jdbc.core.convert.JdbcConverter;
2525
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
26+
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
2627
import org.springframework.data.jdbc.repository.query.DefaultRowMapperFactory;
2728
import org.springframework.data.jdbc.repository.query.JdbcQueryMethod;
2829
import org.springframework.data.jdbc.repository.query.PartTreeJdbcQuery;
@@ -69,7 +70,7 @@ abstract class JdbcQueryLookupStrategy extends RelationalQueryLookupStrategy {
6970
protected final ValueExpressionDelegate delegate;
7071

7172
JdbcQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
72-
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
73+
RelationalMappingContext context, JdbcConverter converter, JdbcDialect dialect,
7374
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
7475
ValueExpressionDelegate delegate) {
7576

@@ -105,7 +106,7 @@ static class CreateQueryLookupStrategy extends JdbcQueryLookupStrategy {
105106
private final RowMapperFactory rowMapperFactory;
106107

107108
CreateQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
108-
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
109+
RelationalMappingContext context, JdbcConverter converter, JdbcDialect dialect,
109110
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
110111
ValueExpressionDelegate delegate) {
111112

@@ -138,7 +139,7 @@ static class DeclaredQueryLookupStrategy extends JdbcQueryLookupStrategy {
138139
private final RowMapperFactory rowMapperFactory;
139140

140141
DeclaredQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
141-
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
142+
RelationalMappingContext context, JdbcConverter converter, JdbcDialect dialect,
142143
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
143144
@Nullable BeanFactory beanfactory, ValueExpressionDelegate delegate) {
144145
super(publisher, callbacks, context, converter, dialect, queryMappingConfiguration, operations, delegate);
@@ -191,7 +192,7 @@ static class CreateIfNotFoundQueryLookupStrategy extends JdbcQueryLookupStrategy
191192
* @param lookupStrategy must not be {@literal null}.
192193
*/
193194
CreateIfNotFoundQueryLookupStrategy(ApplicationEventPublisher publisher, @Nullable EntityCallbacks callbacks,
194-
RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
195+
RelationalMappingContext context, JdbcConverter converter, JdbcDialect dialect,
195196
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
196197
CreateQueryLookupStrategy createStrategy, DeclaredQueryLookupStrategy lookupStrategy,
197198
ValueExpressionDelegate delegate) {
@@ -222,7 +223,12 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repository
222223
*/
223224
JdbcQueryMethod getJdbcQueryMethod(Method method, RepositoryMetadata repositoryMetadata,
224225
ProjectionFactory projectionFactory, NamedQueries namedQueries) {
225-
return new JdbcQueryMethod(method, repositoryMetadata, projectionFactory, namedQueries, getMappingContext());
226+
return new JdbcQueryMethod(method, repositoryMetadata, projectionFactory, namedQueries, getMappingContext(), getDialect().getSqlTypeResolver());
227+
}
228+
229+
@Override
230+
public JdbcDialect getDialect() {
231+
return (JdbcDialect) super.getDialect();
226232
}
227233

228234
/**
@@ -238,7 +244,9 @@ JdbcQueryMethod getJdbcQueryMethod(Method method, RepositoryMetadata repositoryM
238244
* @param queryMappingConfiguration must not be {@literal null}
239245
* @param operations must not be {@literal null}
240246
* @param beanFactory may be {@literal null}
247+
* @deprecated please, use {@link #create(Key, ApplicationEventPublisher, EntityCallbacks, RelationalMappingContext, JdbcConverter, JdbcDialect, QueryMappingConfiguration, NamedParameterJdbcOperations, BeanFactory, ValueExpressionDelegate)}
241248
*/
249+
@Deprecated(forRemoval = true, since = "4.0")
242250
public static QueryLookupStrategy create(@Nullable Key key, ApplicationEventPublisher publisher,
243251
@Nullable EntityCallbacks callbacks, RelationalMappingContext context, JdbcConverter converter, Dialect dialect,
244252
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
@@ -250,6 +258,52 @@ public static QueryLookupStrategy create(@Nullable Key key, ApplicationEventPubl
250258
Assert.notNull(queryMappingConfiguration, "QueryMappingConfiguration must not be null");
251259
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null");
252260
Assert.notNull(delegate, "ValueExpressionDelegate must not be null");
261+
Assert.state(dialect instanceof JdbcDialect, "Dialect must be an instance of the JdbcDialect");
262+
263+
CreateQueryLookupStrategy createQueryLookupStrategy = new CreateQueryLookupStrategy(publisher, callbacks, context,
264+
converter, (JdbcDialect) dialect, queryMappingConfiguration, operations, delegate);
265+
266+
DeclaredQueryLookupStrategy declaredQueryLookupStrategy = new DeclaredQueryLookupStrategy(publisher, callbacks,
267+
context, converter, (JdbcDialect) dialect, queryMappingConfiguration, operations, beanFactory, delegate);
268+
269+
Key keyToUse = key != null ? key : Key.CREATE_IF_NOT_FOUND;
270+
271+
LOG.debug(String.format("Using the queryLookupStrategy %s", keyToUse));
272+
273+
return switch (keyToUse) {
274+
case CREATE -> createQueryLookupStrategy;
275+
case USE_DECLARED_QUERY -> declaredQueryLookupStrategy;
276+
case CREATE_IF_NOT_FOUND ->
277+
new CreateIfNotFoundQueryLookupStrategy(publisher, callbacks, context, converter, (JdbcDialect) dialect,
278+
queryMappingConfiguration, operations, createQueryLookupStrategy, declaredQueryLookupStrategy, delegate);
279+
};
280+
}
281+
282+
/**
283+
* Creates a {@link QueryLookupStrategy} based on the provided
284+
* {@link org.springframework.data.repository.query.QueryLookupStrategy.Key}.
285+
*
286+
* @param key the key that decides what {@link QueryLookupStrategy} shozld be used.
287+
* @param publisher must not be {@literal null}
288+
* @param callbacks may be {@literal null}
289+
* @param context must not be {@literal null}
290+
* @param converter must not be {@literal null}
291+
* @param dialect must not be {@literal null}
292+
* @param queryMappingConfiguration must not be {@literal null}
293+
* @param operations must not be {@literal null}
294+
* @param beanFactory may be {@literal null}
295+
*/
296+
public static QueryLookupStrategy create(@Nullable Key key, ApplicationEventPublisher publisher,
297+
@Nullable EntityCallbacks callbacks, RelationalMappingContext context, JdbcConverter converter, JdbcDialect dialect,
298+
QueryMappingConfiguration queryMappingConfiguration, NamedParameterJdbcOperations operations,
299+
@Nullable BeanFactory beanFactory, ValueExpressionDelegate delegate) {
300+
Assert.notNull(publisher, "ApplicationEventPublisher must not be null");
301+
Assert.notNull(context, "RelationalMappingContextPublisher must not be null");
302+
Assert.notNull(converter, "JdbcConverter must not be null");
303+
Assert.notNull(dialect, "Dialect must not be null");
304+
Assert.notNull(queryMappingConfiguration, "QueryMappingConfiguration must not be null");
305+
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null");
306+
Assert.notNull(delegate, "ValueExpressionDelegate must not be null");
253307

254308
CreateQueryLookupStrategy createQueryLookupStrategy = new CreateQueryLookupStrategy(publisher, callbacks, context,
255309
converter, dialect, queryMappingConfiguration, operations, delegate);

0 commit comments

Comments
 (0)