Skip to content

Commit 96281f8

Browse files
committed
spring-projectsGH-2020 Added SqlTypeResolver abstraction
1 parent f3dc789 commit 96281f8

File tree

10 files changed

+325
-70
lines changed

10 files changed

+325
-70
lines changed

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

+40-8
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
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.relational.core.dialect.SqlTypeResolver;
2425
import org.springframework.data.relational.repository.query.RelationalParameters;
2526
import org.springframework.data.repository.query.Parameter;
2627
import org.springframework.data.repository.query.ParametersSource;
2728
import org.springframework.data.util.Lazy;
2829
import org.springframework.data.util.TypeInformation;
30+
import org.springframework.util.Assert;
2931

3032
/**
3133
* Custom extension of {@link RelationalParameters}.
@@ -36,13 +38,28 @@
3638
public class JdbcParameters extends RelationalParameters {
3739

3840
/**
39-
* Creates a new {@link JdbcParameters} instance from the given {@link ParametersSource}.
41+
* Creates a new {@link JdbcParameters} instance from the given {@link ParametersSource}. Uses the
42+
* {@link SqlTypeResolver#DEFAULT default SqlTypeResolver}.
4043
*
4144
* @param parametersSource must not be {@literal null}.
4245
*/
4346
public JdbcParameters(ParametersSource parametersSource) {
4447
super(parametersSource,
45-
methodParameter -> new JdbcParameter(methodParameter, parametersSource.getDomainTypeInformation()));
48+
methodParameter -> new JdbcParameter(methodParameter, parametersSource.getDomainTypeInformation(), Lazy.of(SqlTypeResolver.DEFAULT)));
49+
}
50+
51+
/**
52+
* Creates a new {@link JdbcParameters} instance from the given {@link ParametersSource} and given {@link SqlTypeResolver}.
53+
*
54+
* @param parametersSource must not be {@literal null}.
55+
* @param sqlTypeResolver must not be {@literal null}.
56+
*/
57+
public JdbcParameters(ParametersSource parametersSource, Lazy<SqlTypeResolver> sqlTypeResolver) {
58+
super(parametersSource,
59+
methodParameter -> new JdbcParameter(methodParameter, parametersSource.getDomainTypeInformation(), sqlTypeResolver));
60+
61+
Assert.notNull(sqlTypeResolver, "SqlTypeResolver must not be null");
62+
Assert.notNull(parametersSource, "ParametersSource must not be null");
4663
}
4764

4865
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -69,27 +86,42 @@ protected JdbcParameters createFrom(List<RelationalParameter> parameters) {
6986
*/
7087
public static class JdbcParameter extends RelationalParameter {
7188

72-
private final SQLType sqlType;
89+
private final Lazy<SQLType> sqlType;
7390
private final Lazy<SQLType> actualSqlType;
7491

7592
/**
7693
* Creates a new {@link RelationalParameter}.
7794
*
7895
* @param parameter must not be {@literal null}.
7996
*/
80-
JdbcParameter(MethodParameter parameter, TypeInformation<?> domainType) {
97+
JdbcParameter(MethodParameter parameter, TypeInformation<?> domainType, Lazy<SqlTypeResolver> sqlTypeResolver) {
8198
super(parameter, domainType);
8299

83100
TypeInformation<?> typeInformation = getTypeInformation();
84101

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

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

91123
public SQLType getSqlType() {
92-
return sqlType;
124+
return sqlType.get();
93125
}
94126

95127
public SQLType getActualSqlType() {

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,27 @@
1717

1818
import java.lang.annotation.Annotation;
1919
import java.lang.reflect.Method;
20+
import java.util.List;
2021
import java.util.Map;
2122
import java.util.Optional;
2223

2324
import org.springframework.core.annotation.AnnotatedElementUtils;
2425
import org.springframework.core.annotation.AnnotationUtils;
2526
import org.springframework.data.mapping.context.MappingContext;
2627
import org.springframework.data.projection.ProjectionFactory;
28+
import org.springframework.data.relational.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;
3032
import org.springframework.data.relational.repository.query.RelationalEntityMetadata;
3133
import org.springframework.data.relational.repository.query.SimpleRelationalEntityMetadata;
3234
import org.springframework.data.repository.core.NamedQueries;
3335
import org.springframework.data.repository.core.RepositoryMetadata;
36+
import org.springframework.data.repository.query.Parameter;
3437
import org.springframework.data.repository.query.Parameters;
3538
import org.springframework.data.repository.query.ParametersSource;
3639
import org.springframework.data.repository.query.QueryMethod;
40+
import org.springframework.data.util.Lazy;
3741
import org.springframework.jdbc.core.ResultSetExtractor;
3842
import org.springframework.jdbc.core.RowMapper;
3943
import org.springframework.lang.Nullable;
@@ -62,22 +66,39 @@ public class JdbcQueryMethod extends QueryMethod {
6266
private @Nullable RelationalEntityMetadata<?> metadata;
6367
private final boolean modifyingQuery;
6468

69+
private final SqlTypeResolver sqlTypeResolver;
70+
6571
// TODO: Remove NamedQueries and put it into JdbcQueryLookupStrategy
6672
public JdbcQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
6773
NamedQueries namedQueries,
6874
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext) {
6975

76+
super(method, metadata, factory);
77+
this.namedQueries = namedQueries;
78+
this.method = method;
79+
this.mappingContext = mappingContext;
80+
this.annotationCache = new ConcurrentReferenceHashMap<>();
81+
this.sqlTypeResolver = SqlTypeResolver.DEFAULT;
82+
this.modifyingQuery = AnnotationUtils.findAnnotation(method, Modifying.class) != null;
83+
}
84+
85+
public JdbcQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
86+
NamedQueries namedQueries,
87+
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext,
88+
SqlTypeResolver sqlTypeResolver) {
89+
7090
super(method, metadata, factory);
7191
this.namedQueries = namedQueries;
7292
this.method = method;
7393
this.mappingContext = mappingContext;
7494
this.annotationCache = new ConcurrentReferenceHashMap<>();
7595
this.modifyingQuery = AnnotationUtils.findAnnotation(method, Modifying.class) != null;
96+
this.sqlTypeResolver = sqlTypeResolver;
7697
}
7798

7899
@Override
79100
protected Parameters<?, ?> createParameters(ParametersSource parametersSource) {
80-
return new JdbcParameters(parametersSource);
101+
return new JdbcParameters(parametersSource, Lazy.of(() -> this.sqlTypeResolver));
81102
}
82103

83104
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2020-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+
17+
package org.springframework.data.jdbc.repository.query;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
import java.sql.SQLType;
25+
26+
/**
27+
*
28+
* @author Mikhail Polivakha
29+
*/
30+
@Documented
31+
@Target(ElementType.PARAMETER)
32+
@Retention(RetentionPolicy.RUNTIME)
33+
public @interface SqlType {
34+
35+
/**
36+
* Returns the {@code SQLType} name that represents a SQL data type.
37+
*
38+
* @return The name of this {@code SQLType}.
39+
*/
40+
String getName();
41+
42+
/**
43+
* Returns the name of the vendor that supports this data type. The value
44+
* returned typically is the package name for this vendor.
45+
*
46+
* @return The name of the vendor for this data type
47+
*/
48+
String getVendor();
49+
50+
/**
51+
* Returns the vendor specific type number for the data type.
52+
*
53+
* @return An Integer representing the vendor specific data type
54+
*/
55+
int getVendorTypeNumber();
56+
}

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

+1-59
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.data.jdbc.core.convert.JdbcConverter;
4040
import org.springframework.data.jdbc.core.mapping.JdbcValue;
4141
import org.springframework.data.jdbc.support.JdbcUtil;
42+
import org.springframework.data.relational.core.dialect.SqlTypeResolver;
4243
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
4344
import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
4445
import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor;
@@ -91,43 +92,6 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
9192
private final CachedResultSetExtractorFactory cachedResultSetExtractorFactory;
9293
private final ValueExpressionDelegate delegate;
9394

94-
/**
95-
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
96-
* and {@link RowMapper}.
97-
*
98-
* @param queryMethod must not be {@literal null}.
99-
* @param operations must not be {@literal null}.
100-
* @param defaultRowMapper can be {@literal null} (only in case of a modifying query).
101-
* @deprecated since 3.4, use the constructors accepting {@link ValueExpressionDelegate} instead.
102-
*/
103-
@Deprecated(since = "3.4")
104-
public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
105-
@Nullable RowMapper<?> defaultRowMapper, JdbcConverter converter,
106-
QueryMethodEvaluationContextProvider evaluationContextProvider) {
107-
this(queryMethod.getRequiredQuery(), queryMethod, operations, result -> (RowMapper<Object>) defaultRowMapper,
108-
converter, evaluationContextProvider);
109-
}
110-
111-
/**
112-
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
113-
* and {@link RowMapperFactory}.
114-
*
115-
* @param queryMethod must not be {@literal null}.
116-
* @param operations must not be {@literal null}.
117-
* @param rowMapperFactory must not be {@literal null}.
118-
* @param converter must not be {@literal null}.
119-
* @param evaluationContextProvider must not be {@literal null}.
120-
* @since 2.3
121-
* @deprecated use alternative constructor
122-
*/
123-
@Deprecated(since = "3.4")
124-
public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
125-
RowMapperFactory rowMapperFactory, JdbcConverter converter,
126-
QueryMethodEvaluationContextProvider evaluationContextProvider) {
127-
this(queryMethod.getRequiredQuery(), queryMethod, operations, rowMapperFactory, converter,
128-
evaluationContextProvider);
129-
}
130-
13195
/**
13296
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
13397
* and {@link RowMapperFactory}.
@@ -197,28 +161,6 @@ public StringBasedJdbcQuery(String query, JdbcQueryMethod queryMethod, NamedPara
197161
this.delegate = delegate;
198162
}
199163

200-
/**
201-
* Creates a new {@link StringBasedJdbcQuery} for the given {@link JdbcQueryMethod}, {@link RelationalMappingContext}
202-
* and {@link RowMapperFactory}.
203-
*
204-
* @param query must not be {@literal null} or empty.
205-
* @param queryMethod must not be {@literal null}.
206-
* @param operations must not be {@literal null}.
207-
* @param rowMapperFactory must not be {@literal null}.
208-
* @param converter must not be {@literal null}.
209-
* @param evaluationContextProvider must not be {@literal null}.
210-
* @since 3.4
211-
* @deprecated since 3.4, use the constructors accepting {@link ValueExpressionDelegate} instead.
212-
*/
213-
@Deprecated(since = "3.4")
214-
public StringBasedJdbcQuery(String query, JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
215-
RowMapperFactory rowMapperFactory, JdbcConverter converter,
216-
QueryMethodEvaluationContextProvider evaluationContextProvider) {
217-
this(query, queryMethod, operations, rowMapperFactory, converter, new CachingValueExpressionDelegate(
218-
new QueryMethodValueEvaluationContextAccessor(new StandardEnvironment(), rootObject -> evaluationContextProvider
219-
.getEvaluationContext(queryMethod.getParameters(), new Object[] { rootObject })),
220-
ValueExpressionParser.create()));
221-
}
222164

223165
@Override
224166
public Object execute(Object[] objects) {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repository
264264
*/
265265
JdbcQueryMethod getJdbcQueryMethod(Method method, RepositoryMetadata repositoryMetadata,
266266
ProjectionFactory projectionFactory, NamedQueries namedQueries) {
267-
return new JdbcQueryMethod(method, repositoryMetadata, projectionFactory, namedQueries, getMappingContext());
267+
return new JdbcQueryMethod(method, repositoryMetadata, projectionFactory, namedQueries, getMappingContext(), getDialect().getSqlTypeResolver());
268268
}
269269

270270
/**

0 commit comments

Comments
 (0)