Skip to content

Commit 95fb0c4

Browse files
committed
Removed dialect dependency from QueryMapper.
The refactoring does not honour the distinction between the default escaper and the like escaper, but since ValueFunctions are only used in the context of LIKE operations I don't see the point. See #1601
1 parent cdb7f7c commit 95fb0c4

File tree

8 files changed

+103
-44
lines changed

8 files changed

+103
-44
lines changed

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

+20-19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import java.util.Map;
2525
import java.util.Objects;
26+
import java.util.function.Function;
2627

2728
import org.springframework.data.domain.Sort;
2829
import org.springframework.data.jdbc.core.mapping.JdbcValue;
@@ -60,26 +61,38 @@
6061
public class QueryMapper {
6162

6263
private final JdbcConverter converter;
63-
private final Dialect dialect;
6464
private final MappingContext<? extends RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
6565

6666
/**
6767
* Creates a new {@link QueryMapper} with the given {@link JdbcConverter}.
6868
*
6969
* @param dialect must not be {@literal null}.
7070
* @param converter must not be {@literal null}.
71+
* @deprecated use {@link QueryMapper(JdbcConverter)} instead.
7172
*/
72-
@SuppressWarnings({ "unchecked", "rawtypes" })
73+
@Deprecated(since="3.2")
7374
public QueryMapper(Dialect dialect, JdbcConverter converter) {
7475

7576
Assert.notNull(dialect, "Dialect must not be null");
7677
Assert.notNull(converter, "JdbcConverter must not be null");
7778

7879
this.converter = converter;
79-
this.dialect = dialect;
8080
this.mappingContext = (MappingContext) converter.getMappingContext();
8181
}
8282

83+
/**
84+
* Creates a new {@link QueryMapper} with the given {@link JdbcConverter}.
85+
*
86+
* @param converter must not be {@literal null}.
87+
*/
88+
public QueryMapper( JdbcConverter converter) {
89+
90+
Assert.notNull(converter, "JdbcConverter must not be null");
91+
92+
this.converter = converter;
93+
this.mappingContext = converter.getMappingContext();
94+
}
95+
8396
/**
8497
* Map the {@link Sort} object to apply field name mapping using {@link RelationalPersistentEntity the type to read}.
8598
*
@@ -295,16 +308,13 @@ private Condition mapCondition(CriteriaDefinition criteria, MapSqlParameterSourc
295308

296309
mappedValue = convertValue(comparator, settableValue.getValue(), propertyField.getTypeHint());
297310
sqlType = getTypeHint(mappedValue, actualType.getType(), settableValue);
298-
} else if (criteria.getValue() instanceof ValueFunction) {
311+
} else if (criteria.getValue() instanceof ValueFunction valueFunction) {
299312

300-
ValueFunction<Object> valueFunction = (ValueFunction<Object>) criteria.getValue();
301-
Object value = valueFunction.apply(getEscaper(comparator));
302-
303-
mappedValue = convertValue(comparator, value, propertyField.getTypeHint());
313+
mappedValue = valueFunction;
304314
sqlType = propertyField.getSqlType();
305315

306-
} else if (propertyField instanceof MetadataBackedField //
307-
&& ((MetadataBackedField) propertyField).property != null //
316+
} else if (propertyField instanceof MetadataBackedField metadataBackedField //
317+
&& metadataBackedField.property != null //
308318
&& (criteria.getValue() == null || !criteria.getValue().getClass().isArray())) {
309319

310320
RelationalPersistentProperty property = ((MetadataBackedField) propertyField).property;
@@ -431,15 +441,6 @@ private Condition mapEmbeddedObjectCondition(CriteriaDefinition criteria, MapSql
431441
return Conditions.nest(condition);
432442
}
433443

434-
private Escaper getEscaper(Comparator comparator) {
435-
436-
if (comparator == Comparator.LIKE || comparator == Comparator.NOT_LIKE) {
437-
return dialect.getLikeEscaper();
438-
}
439-
440-
return Escaper.DEFAULT;
441-
}
442-
443444
@Nullable
444445
private Object convertValue(Comparator comparator, @Nullable Object value, TypeInformation<?> typeHint) {
445446

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class SqlGenerator {
113113
this.renderContext = new RenderContextFactory(dialect).createRenderContext();
114114
this.sqlRenderer = SqlRenderer.create(renderContext);
115115
this.columns = new Columns(entity, mappingContext, converter);
116-
this.queryMapper = new QueryMapper(dialect, converter);
116+
this.queryMapper = new QueryMapper(converter);
117117
this.dialect = dialect;
118118
}
119119

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2023 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 org.springframework.data.relational.core.dialect.Escaper;
20+
import org.springframework.data.relational.core.query.ValueFunction;
21+
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
22+
23+
/**
24+
* This {@link SqlParameterSource} will apply escaping to it's values.
25+
*
26+
* @author Jens Schauder
27+
* @since 3.2
28+
*/
29+
public class EscapingParameterSource implements SqlParameterSource {
30+
private final SqlParameterSource parameterSource;
31+
private final Escaper escaper;
32+
33+
public EscapingParameterSource(SqlParameterSource parameterSource, Escaper escaper) {
34+
35+
this.parameterSource = parameterSource;
36+
this.escaper = escaper;
37+
}
38+
39+
@Override
40+
public boolean hasValue(String paramName) {
41+
return parameterSource.hasValue(paramName);
42+
}
43+
44+
@Override
45+
public Object getValue(String paramName) throws IllegalArgumentException {
46+
47+
Object value = parameterSource.getValue(paramName);
48+
if (value instanceof ValueFunction<?>) {
49+
return ((ValueFunction<?>) value).apply(escaper);
50+
}
51+
return value;
52+
}
53+
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
102102
this.accessor = accessor;
103103

104104
this.entityMetadata = entityMetadata;
105-
this.queryMapper = new QueryMapper(dialect, converter);
105+
this.queryMapper = new QueryMapper(converter);
106106
this.renderContextFactory = new RenderContextFactory(dialect);
107107
this.isSliceQuery = isSliceQuery;
108108
this.returnedType = returnedType;

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@
1515
*/
1616
package org.springframework.data.jdbc.repository.query;
1717

18+
import org.springframework.data.relational.core.dialect.Dialect;
19+
import org.springframework.data.relational.core.dialect.Escaper;
1820
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
1921

2022
/**
2123
* Value object encapsulating a query containing named parameters and a{@link SqlParameterSource} to bind the parameters.
2224
*
2325
* @author Mark Paluch
26+
* @author Jens Schauder
2427
* @since 2.0
2528
*/
2629
class ParametrizedQuery {
@@ -38,12 +41,13 @@ String getQuery() {
3841
return query;
3942
}
4043

41-
SqlParameterSource getParameterSource() {
42-
return parameterSource;
43-
}
44-
4544
@Override
4645
public String toString() {
4746
return this.query;
4847
}
48+
49+
public SqlParameterSource getParameterSource(Escaper escaper) {
50+
51+
return new EscapingParameterSource(parameterSource, escaper);
52+
}
4953
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public Object execute(Object[] values) {
126126
ParametrizedQuery query = createQuery(accessor, processor.getReturnedType());
127127
JdbcQueryExecution<?> execution = getQueryExecution(processor, accessor);
128128

129-
return execution.execute(query.getQuery(), query.getParameterSource());
129+
return execution.execute(query.getQuery(), query.getParameterSource(dialect.getLikeEscaper()));
130130
}
131131

132132
private JdbcQueryExecution<?> getQueryExecution(ResultProcessor processor,
@@ -164,7 +164,7 @@ private JdbcQueryExecution<?> getQueryExecution(ResultProcessor processor,
164164

165165
ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted());
166166
Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(),
167-
countQuery.getParameterSource());
167+
countQuery.getParameterSource(dialect.getLikeEscaper()));
168168

169169
return converter.getConversionService().convert(count, Long.class);
170170
});

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class QueryMapperUnitTests {
5050
JdbcMappingContext context = new JdbcMappingContext();
5151
JdbcConverter converter = new BasicJdbcConverter(context, mock(RelationResolver.class));
5252

53-
QueryMapper mapper = new QueryMapper(PostgresDialect.INSTANCE, converter);
53+
QueryMapper mapper = new QueryMapper(converter);
5454
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
5555

5656
@Test // DATAJDBC-318

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java

+17-16
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.data.jdbc.core.mapping.AggregateReference;
3737
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
3838
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
39+
import org.springframework.data.relational.core.dialect.Escaper;
3940
import org.springframework.data.relational.core.dialect.H2Dialect;
4041
import org.springframework.data.relational.core.mapping.Embedded;
4142
import org.springframework.data.relational.core.mapping.MappedCollection;
@@ -93,7 +94,7 @@ public void createQueryByAggregateReference() throws Exception {
9394
softly.assertThat(query.getQuery())
9495
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference");
9596

96-
softly.assertThat(query.getParameterSource().getValue("hobby_reference")).isEqualTo("twentythree");
97+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("hobby_reference")).isEqualTo("twentythree");
9798
});
9899
}
99100

@@ -112,8 +113,8 @@ void createQueryWithPessimisticWriteLock() throws Exception {
112113

113114
softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE");
114115

115-
softly.assertThat(query.getParameterSource().getValue("first_name")).isEqualTo(firstname);
116-
softly.assertThat(query.getParameterSource().getValue("last_name")).isEqualTo(lastname);
116+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo(firstname);
117+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("last_name")).isEqualTo(lastname);
117118
});
118119
}
119120

@@ -133,8 +134,8 @@ void createQueryWithPessimisticReadLock() throws Exception {
133134
// this is also for update since h2 dialect does not distinguish between lockmodes
134135
softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE");
135136

136-
softly.assertThat(query.getParameterSource().getValue("first_name")).isEqualTo(firstname);
137-
softly.assertThat(query.getParameterSource().getValue("age")).isEqualTo(age);
137+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo(firstname);
138+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("age")).isEqualTo(age);
138139
});
139140
}
140141

@@ -165,7 +166,7 @@ public void createQueryForQueryByAggregateReference() throws Exception {
165166
softly.assertThat(query.getQuery())
166167
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference");
167168

168-
softly.assertThat(query.getParameterSource().getValue("hobby_reference")).isEqualTo("twentythree");
169+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("hobby_reference")).isEqualTo("twentythree");
169170
});
170171
}
171172

@@ -182,7 +183,7 @@ public void createQueryForQueryByAggregateReferenceId() throws Exception {
182183
softly.assertThat(query.getQuery())
183184
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference");
184185

185-
softly.assertThat(query.getParameterSource().getValue("hobby_reference")).isEqualTo("twentythree");
186+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("hobby_reference")).isEqualTo("twentythree");
186187
});
187188
}
188189

@@ -270,8 +271,8 @@ public void createsQueryToFindAllEntitiesByDateAttributeBetween() throws Excepti
270271
softly.assertThat(query.getQuery())
271272
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" BETWEEN :date_of_birth AND :date_of_birth1");
272273

273-
softly.assertThat(query.getParameterSource().getValue("date_of_birth")).isEqualTo(from);
274-
softly.assertThat(query.getParameterSource().getValue("date_of_birth1")).isEqualTo(to);
274+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("date_of_birth")).isEqualTo(from);
275+
softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("date_of_birth1")).isEqualTo(to);
275276
});
276277
}
277278

@@ -405,7 +406,7 @@ public void appendsLikeOperatorParameterWithPercentSymbolForStartingWithQuery()
405406
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
406407

407408
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
408-
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("Jo%");
409+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("Jo%");
409410
}
410411

411412
@Test // DATAJDBC-318
@@ -428,7 +429,7 @@ public void prependsLikeOperatorParameterWithPercentSymbolForEndingWithQuery() t
428429
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
429430

430431
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
431-
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%hn");
432+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("%hn");
432433
}
433434

434435
@Test // DATAJDBC-318
@@ -451,7 +452,7 @@ public void wrapsLikeOperatorParameterWithPercentSymbolsForContainingQuery() thr
451452
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
452453

453454
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
454-
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%");
455+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("%oh%");
455456
}
456457

457458
@Test // DATAJDBC-318
@@ -474,7 +475,7 @@ public void wrapsLikeOperatorParameterWithPercentSymbolsForNotContainingQuery()
474475
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
475476

476477
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name");
477-
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%");
478+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("%oh%");
478479
}
479480

480481
@Test // DATAJDBC-318
@@ -638,8 +639,8 @@ public void createsQueryByEmbeddedObject() throws Exception {
638639
.contains(TABLE + ".\"USER_STREET\" = :user_street", //
639640
" AND ", //
640641
TABLE + ".\"USER_CITY\" = :user_city");
641-
assertThat(query.getParameterSource().getValue("user_street")).isEqualTo("Hello");
642-
assertThat(query.getParameterSource().getValue("user_city")).isEqualTo("World");
642+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("user_street")).isEqualTo("Hello");
643+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("user_city")).isEqualTo("World");
643644
}
644645

645646
@Test // DATAJDBC-318
@@ -653,7 +654,7 @@ public void createsQueryByEmbeddedProperty() throws Exception {
653654
String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"USER_STREET\" = :user_street";
654655

655656
assertThat(query.getQuery()).isEqualTo(expectedSql);
656-
assertThat(query.getParameterSource().getValue("user_street")).isEqualTo("Hello");
657+
assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("user_street")).isEqualTo("Hello");
657658
}
658659

659660
@Test // DATAJDBC-534

0 commit comments

Comments
 (0)