Skip to content

Commit 1794cd9

Browse files
herdersothawo
authored andcommitted
Support collection parameters in @query methods.
Original Pull Request #1856 Closes #1858 (cherry picked from commit 6f84a1c) (cherry picked from commit 254948d) (cherry picked from commit 979c164) (cherry picked from commit d6cfc20)
1 parent 724f9bc commit 1794cd9

File tree

2 files changed

+100
-23
lines changed

2 files changed

+100
-23
lines changed

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
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.elasticsearch.core.convert.DateTimeConverters;
@@ -27,6 +29,7 @@
2729

2830
/**
2931
* @author Peter-Josef Meisch
32+
* @author Niklas Herder
3033
*/
3134
final public class StringQueryUtil {
3235

@@ -70,6 +73,28 @@ private static String getParameterWithIndex(ParameterAccessor accessor, int inde
7073
// noinspection ConstantConditions
7174
if (parameter != null) {
7275

76+
parameterValue = convert(parameter);
77+
}
78+
79+
return parameterValue;
80+
81+
}
82+
83+
private static String convert(Object parameter) {
84+
if (Collection.class.isAssignableFrom(parameter.getClass())) {
85+
Collection<?> collectionParam = (Collection<?>) parameter;
86+
StringBuilder sb = new StringBuilder("[");
87+
sb.append(collectionParam.stream().map(o -> {
88+
if (o instanceof String) {
89+
return "\"" + convert(o) + "\"";
90+
} else {
91+
return convert(o);
92+
}
93+
}).collect(Collectors.joining(",")));
94+
sb.append("]");
95+
return sb.toString();
96+
} else {
97+
String parameterValue = "null";
7398
if (conversionService.canConvert(parameter.getClass(), String.class)) {
7499
String converted = conversionService.convert(parameter, String.class);
75100

@@ -79,11 +104,10 @@ private static String getParameterWithIndex(ParameterAccessor accessor, int inde
79104
} else {
80105
parameterValue = parameter.toString();
81106
}
82-
}
83-
84-
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
85-
return parameterValue;
86107

108+
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
109+
return parameterValue;
110+
}
87111
}
88112

89113
}

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

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import lombok.Setter;
2525

2626
import java.lang.reflect.Method;
27+
import java.util.ArrayList;
2728
import java.util.Arrays;
2829
import java.util.Collection;
2930
import java.util.HashMap;
@@ -50,10 +51,12 @@
5051
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
5152
import org.springframework.data.repository.Repository;
5253
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
54+
import org.springframework.lang.Nullable;
5355

5456
/**
5557
* @author Christoph Strobl
5658
* @author Peter-Josef Meisch
59+
* @author Niklas Herder
5760
*/
5861
@RunWith(MockitoJUnitRunner.class)
5962
public class ElasticsearchStringQueryUnitTests {
@@ -97,7 +100,39 @@ public void shouldEscapeStringsInQueryParameters() throws Exception {
97100
.isEqualTo("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"hello \\\"Stranger\\\"\"}}]}}");
98101
}
99102

100-
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
103+
@Test // #1858
104+
public void shouldOnlyEscapeStringQueryParameters() throws Exception {
105+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAge", Integer.valueOf(30));
106+
107+
assertThat(query).isInstanceOf(StringQuery.class);
108+
assertThat(((StringQuery) query).getSource()).isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'age' : 30 } } } }");
109+
110+
}
111+
112+
@Test // #1858
113+
public void shouldOnlyEscapeStringCollectionQueryParameters() throws Exception {
114+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAgeIn",
115+
new ArrayList<>(Arrays.asList(30, 35, 40)));
116+
117+
assertThat(query).isInstanceOf(StringQuery.class);
118+
assertThat(((StringQuery) query).getSource())
119+
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'age' : [30,35,40] } } } }");
120+
121+
}
122+
123+
@Test // #1858
124+
public void shouldEscapeStringsInCollectionsQueryParameters() throws Exception {
125+
126+
final List<String> another_string = Arrays.asList("hello \"Stranger\"", "Another string");
127+
List<String> params = new ArrayList<>(another_string);
128+
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByNameIn", params);
129+
130+
assertThat(query).isInstanceOf(StringQuery.class);
131+
assertThat(((StringQuery) query).getSource()).isEqualTo(
132+
"{ 'bool' : { 'must' : { 'terms' : { 'name' : [\"hello \\\"Stranger\\\"\",\"Another string\"] } } } }");
133+
}
134+
135+
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
101136
throws NoSuchMethodException {
102137

103138
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(size -> new Class[size]);
@@ -117,24 +152,55 @@ private ElasticsearchQueryMethod getQueryMethod(String name, Class<?>... paramet
117152
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
118153
}
119154

155+
private interface SampleRepository extends Repository<Person, String> {
156+
157+
@Query("{ 'bool' : { 'must' : { 'term' : { 'age' : ?0 } } } }")
158+
List<Person> findByAge(Integer age);
159+
160+
@Query("{ 'bool' : { 'must' : { 'term' : { 'age' : ?0 } } } }")
161+
List<Person> findByAgeIn(ArrayList<Integer> age);
162+
163+
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
164+
Person findByName(String name);
165+
166+
@Query("{ 'bool' : { 'must' : { 'terms' : { 'name' : ?0 } } } }")
167+
Person findByNameIn(ArrayList<String> names);
168+
169+
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
170+
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
171+
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
172+
173+
@Query("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"?0\"}}]}}")
174+
List<Book> findByPrefix(String prefix);
175+
}
176+
120177
/**
121178
* @author Rizwan Idrees
122179
* @author Mohsin Husen
123180
* @author Artur Konczak
181+
* @author Niklas Herder
124182
*/
125183

126184
@Document(indexName = "test-index-person-query-unittest", type = "user", shards = 1, replicas = 0,
127185
refreshInterval = "-1")
128186
static class Person {
129187

130-
@Id private String id;
131-
132-
private String name;
188+
@Nullable public int age;
189+
@Nullable @Id private String id;
190+
@Nullable private String name;
191+
@Nullable @Field(type = FieldType.Nested) private List<Car> car;
192+
@Nullable @Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
133193

134-
@Field(type = FieldType.Nested) private List<Car> car;
194+
@Nullable
195+
public int getAge() {
196+
return age;
197+
}
135198

136-
@Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
199+
public void setAge(int age) {
200+
this.age = age;
201+
}
137202

203+
@Nullable
138204
public String getId() {
139205
return id;
140206
}
@@ -168,19 +234,6 @@ public void setBooks(List<Book> books) {
168234
}
169235
}
170236

171-
private interface SampleRepository extends Repository<Person, String> {
172-
173-
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
174-
Person findByName(String name);
175-
176-
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
177-
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
178-
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
179-
180-
@Query("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"?0\"}}]}}")
181-
List<Book> findByPrefix(String prefix);
182-
}
183-
184237
/**
185238
* @author Rizwan Idrees
186239
* @author Mohsin Husen

0 commit comments

Comments
 (0)