Skip to content

Commit 3b59581

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 3b59581

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,18 @@
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;
21+
import java.util.stream.Collectors;
2022

2123
import org.springframework.core.convert.support.GenericConversionService;
2224
import org.springframework.data.repository.query.ParameterAccessor;
2325
import org.springframework.util.NumberUtils;
2426

2527
/**
2628
* @author Peter-Josef Meisch
29+
* @author Niklas Herder
2730
*/
2831
final public class StringQueryUtil {
2932

@@ -53,6 +56,22 @@ private static String getParameterWithIndex(ParameterAccessor accessor, int inde
5356
// noinspection ConstantConditions
5457
if (parameter != null) {
5558

59+
parameterValue = convert(parameter);
60+
}
61+
62+
return parameterValue;
63+
64+
}
65+
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(o -> "\"" + convert(o) + "\"").collect(Collectors.joining(",")));
71+
sb.append("]");
72+
return sb.toString();
73+
} else {
74+
String parameterValue = "null";
5675
if (conversionService.canConvert(parameter.getClass(), String.class)) {
5776
String converted = conversionService.convert(parameter, String.class);
5877

@@ -62,11 +81,10 @@ private static String getParameterWithIndex(ParameterAccessor accessor, int inde
6281
} else {
6382
parameterValue = parameter.toString();
6483
}
65-
}
66-
67-
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
68-
return parameterValue;
6984

85+
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
86+
return parameterValue;
87+
}
7088
}
7189

7290
}

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
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;
2324
import java.util.HashMap;
@@ -51,6 +52,7 @@
5152
/**
5253
* @author Christoph Strobl
5354
* @author Peter-Josef Meisch
55+
* @author Niklas Herder
5456
*/
5557
@ExtendWith(MockitoExtension.class)
5658
public class ElasticsearchStringQueryUnitTests {
@@ -95,14 +97,28 @@ 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 // #1858
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()).isEqualTo(
110+
"{ '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);
102117
ElasticsearchQueryMethod queryMethod = getQueryMethod(methodName, argTypes);
103118
ElasticsearchStringQuery elasticsearchStringQuery = queryForMethod(queryMethod);
104119
return elasticsearchStringQuery.createQuery(new ElasticsearchParametersParameterAccessor(queryMethod, args));
105120
}
121+
106122
private ElasticsearchStringQuery queryForMethod(ElasticsearchQueryMethod queryMethod) {
107123
return new ElasticsearchStringQuery(queryMethod, operations, queryMethod.getAnnotatedQuery());
108124
}
@@ -119,6 +135,9 @@ private interface SampleRepository extends Repository<Person, String> {
119135
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
120136
Person findByName(String name);
121137

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

0 commit comments

Comments
 (0)