Skip to content

Commit 07598d5

Browse files
committed
Support collection parameters in @query methods
This adds a test and fix so that collection parameters are supported and quoted correctly, at least for `Collection<String>`. Previously the `StringQueryUtil` class would just call `.toString()` on the parameter and escape the `"` characters in the result, which would cause a syntax error in the query string. This changes so that the class checks if the parameter is a `Collection` and if so starts a Json array and adds elements to it by calling `convert()` on each element.
1 parent a16a87f commit 07598d5

File tree

2 files changed

+50
-12
lines changed

2 files changed

+50
-12
lines changed

src/main/java/org/springframework/data/elasticsearch/repository/support/StringQueryUtil.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
*/
1616
package org.springframework.data.elasticsearch.repository.support;
1717

18+
import java.util.Collection;
1819
import java.util.regex.Matcher;
1920
import java.util.regex.Pattern;
2021

22+
import java.util.stream.Collectors;
23+
import org.springframework.core.convert.converter.Converter;
2124
import org.springframework.core.convert.support.GenericConversionService;
2225
import org.springframework.data.repository.query.ParameterAccessor;
2326
import org.springframework.util.NumberUtils;
@@ -53,20 +56,37 @@ private static String getParameterWithIndex(ParameterAccessor accessor, int inde
5356
// noinspection ConstantConditions
5457
if (parameter != null) {
5558

56-
if (conversionService.canConvert(parameter.getClass(), String.class)) {
57-
String converted = conversionService.convert(parameter, String.class);
59+
parameterValue = convert(parameter);
60+
}
5861

59-
if (converted != null) {
60-
parameterValue = converted;
61-
}
62-
} else {
63-
parameterValue = parameter.toString();
64-
}
65-
}
66-
67-
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
6862
return parameterValue;
6963

7064
}
7165

66+
private static String convert(Object parameter) {
67+
if (Collection.class.isAssignableFrom(parameter.getClass())) {
68+
Collection<?> collectionParam = (Collection<?>) parameter;
69+
StringBuilder sb = new StringBuilder("[");
70+
sb.append(collectionParam.stream().map(
71+
o -> "\"" + convert(o) + "\""
72+
).collect(Collectors.joining(",")));
73+
sb.append("]");
74+
return sb.toString();
75+
} else {
76+
String parameterValue = "null";
77+
if (conversionService.canConvert(parameter.getClass(), String.class)) {
78+
String converted = conversionService.convert(parameter, String.class);
79+
80+
if (converted != null) {
81+
parameterValue = converted;
82+
}
83+
} else {
84+
parameterValue = parameter.toString();
85+
}
86+
87+
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
88+
return parameterValue;
89+
}
90+
}
91+
7292
}

src/test/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchStringQueryUnitTests.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import static org.assertj.core.api.Assertions.*;
1919

2020
import java.lang.reflect.Method;
21+
import java.util.ArrayList;
2122
import java.util.Arrays;
2223
import java.util.Collection;
24+
import java.util.Collections;
2325
import java.util.HashMap;
2426
import java.util.List;
2527
import java.util.Map;
@@ -95,7 +97,20 @@ void shouldEscapeStringsInQueryParameters() throws Exception {
9597
.isEqualTo("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"hello \\\"Stranger\\\"\"}}]}}");
9698
}
9799

98-
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
100+
@Test
101+
@DisplayName("should escape Strings in collection query parameters")
102+
void shouldEscapeStringsInCollectionsQueryParameters() throws Exception {
103+
104+
final List<String> another_string = Arrays.asList("hello \"Stranger\"", "Another string");
105+
List<String> params = new ArrayList<>(another_string);
106+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByNameIn", params);
107+
108+
assertThat(query).isInstanceOf(StringQuery.class);
109+
assertThat(((StringQuery) query).getSource())
110+
.isEqualTo("{ 'bool' : { 'must' : { 'terms' : { 'name' : [\"hello \\\"Stranger\\\"\",\"Another string\"] } } } }");
111+
}
112+
113+
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
99114
throws NoSuchMethodException {
100115

101116
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
@@ -119,6 +134,9 @@ private interface SampleRepository extends Repository<Person, String> {
119134
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
120135
Person findByName(String name);
121136

137+
@Query("{ 'bool' : { 'must' : { 'terms' : { 'name' : ?0 } } } }")
138+
Person findByNameIn(ArrayList<String> names);
139+
122140
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
123141
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
124142
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);

0 commit comments

Comments
 (0)