1
0
mirror of synced 2026-05-23 20:53:17 +00:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Jens Schauder 6f89e17451 Release version 4.2.3 (2021.0.3).
See #1850
2021-07-16 11:35:23 +02:00
Jens Schauder 0ad4fcb2eb Prepare 4.2.3 (2021.0.3).
See #1850
2021-07-16 11:34:28 +02:00
Jens Schauder 4c3281f1eb Updated changelog.
See #1850
2021-07-16 11:34:25 +02:00
Peter-Josef Meisch 303438ae63 Use registered converters for parameters of @Query annotated methods.
Original Pull Request #1867
Closes #1866

(cherry picked from commit 27094724dc)
2021-07-14 20:02:44 +02:00
Niklas Herder 254948d1c9 Support collection parameters in @Query methods.
Original Pull Request #1856
Closes #1858

(cherry picked from commit 6f84a1c589)
2021-07-03 18:08:36 +02:00
Sascha Woo 0bb239a674 Add missing hashCode and equals methods to JoinField.
Original Pull Request #1847
Closes #1846

(cherry picked from commit a16a87f3fa)
2021-06-23 20:37:32 +02:00
Mark Paluch 3336ceade8 After release cleanups.
See #1814
2021-06-22 16:05:23 +02:00
Mark Paluch e7398df948 Prepare next development iteration.
See #1814
2021-06-22 16:05:20 +02:00
Mark Paluch a7ed13db83 Release version 4.2.2 (2021.0.2).
See #1814
2021-06-22 15:52:29 +02:00
Mark Paluch 7db3dc1a37 Prepare 4.2.2 (2021.0.2).
See #1814
2021-06-22 15:51:40 +02:00
Mark Paluch 0cabc3372e Updated changelog.
See #1814
2021-06-22 15:51:35 +02:00
Mark Paluch ab2fba6581 Updated changelog.
See #1813
2021-06-22 15:29:55 +02:00
Peter-Josef Meisch 45a0e2213f Adapt XNamedContents used by ReactiveElasticsearchClient for missing entries (terms and aggregations).
Original Pull Request #1837
Closes #1834

(cherry picked from commit 38dc7fb0fb)
2021-06-02 22:18:52 +02:00
Peter-Josef Meisch 8c8c0eba4f update versions table 2021-05-24 18:10:00 +02:00
Mark Paluch 90b366cf5f After release cleanups.
See #1775
2021-05-14 12:34:22 +02:00
Mark Paluch c5d93c5cd2 Prepare next development iteration.
See #1775
2021-05-14 12:34:18 +02:00
12 changed files with 323 additions and 98 deletions
+3 -3
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.2.1</version>
<version>4.2.3</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>2.5.1</version>
<version>2.5.3</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -22,7 +22,7 @@
<elasticsearch>7.12.1</elasticsearch>
<log4j>2.13.3</log4j>
<netty>4.1.52.Final</netty>
<springdata.commons>2.5.1</springdata.commons>
<springdata.commons>2.5.3</springdata.commons>
<testcontainers>1.15.1</testcontainers>
<java-module-name>spring.data.elasticsearch</java-module-name>
</properties>
+1 -1
View File
@@ -34,7 +34,7 @@ The following table shows the Elasticsearch versions that are used by Spring Dat
[cols="^,^,^,^,^",options="header"]
|===
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot
| 2021.0 (Pascal)footnote:cdv[Currently in development] | 4.2.xfootnote:cdv[] | 7.12.1 | 5.3.xfootnote:cdv[] | 2.4.xfootnote:cdv[]
| 2021.0 (Pascal) | 4.2.1 | 7.12.1 | 5.3.7 | 2.5.x
| 2020.0 (Ockham) | 4.1.x | 7.9.3 | 5.3.2 | 2.4.x
| Neumann | 4.0.x | 7.6.2 | 5.2.12 |2.3.x
| Moore | 3.2.x |6.8.12 | 5.2.12| 2.2.x
@@ -20,6 +20,12 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.elasticsearch.client.analytics.InferencePipelineAggregationBuilder;
import org.elasticsearch.client.analytics.ParsedInference;
import org.elasticsearch.client.analytics.ParsedStringStats;
import org.elasticsearch.client.analytics.ParsedTopMetrics;
import org.elasticsearch.client.analytics.StringStatsAggregationBuilder;
import org.elasticsearch.client.analytics.TopMetricsAggregationBuilder;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ContextParser;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
@@ -44,6 +50,8 @@ import org.elasticsearch.search.aggregations.bucket.histogram.HistogramAggregati
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedAutoDateHistogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedHistogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedVariableWidthHistogram;
import org.elasticsearch.search.aggregations.bucket.histogram.VariableWidthHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.missing.MissingAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.missing.ParsedMissing;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
@@ -60,12 +68,7 @@ import org.elasticsearch.search.aggregations.bucket.range.ParsedRange;
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.sampler.InternalSampler;
import org.elasticsearch.search.aggregations.bucket.sampler.ParsedSampler;
import org.elasticsearch.search.aggregations.bucket.terms.DoubleTerms;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedDoubleTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.*;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.aggregations.pipeline.*;
import org.elasticsearch.search.suggest.Suggest;
@@ -81,7 +84,7 @@ import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsea
* <p>
* Original implementation source {@link org.elasticsearch.client.RestHighLevelClient#getDefaultNamedXContents()} by
* {@literal Elasticsearch} (<a href="https://www.elastic.co">https://www.elastic.co</a>) licensed under the Apache
* License, Version 2.0.
* License, Version 2.0. The latest version used from Elasticsearch is 7.10.2.
* </p>
* Modified for usage with {@link ReactiveElasticsearchClient}.
* <p>
@@ -126,9 +129,13 @@ public class NamedXContents {
map.put(HistogramAggregationBuilder.NAME, (p, c) -> ParsedHistogram.fromXContent(p, (String) c));
map.put(DateHistogramAggregationBuilder.NAME, (p, c) -> ParsedDateHistogram.fromXContent(p, (String) c));
map.put(AutoDateHistogramAggregationBuilder.NAME, (p, c) -> ParsedAutoDateHistogram.fromXContent(p, (String) c));
map.put(VariableWidthHistogramAggregationBuilder.NAME,
(p, c) -> ParsedVariableWidthHistogram.fromXContent(p, (String) c));
map.put(StringTerms.NAME, (p, c) -> ParsedStringTerms.fromXContent(p, (String) c));
map.put(LongTerms.NAME, (p, c) -> ParsedLongTerms.fromXContent(p, (String) c));
map.put(DoubleTerms.NAME, (p, c) -> ParsedDoubleTerms.fromXContent(p, (String) c));
map.put(LongRareTerms.NAME, (p, c) -> ParsedLongRareTerms.fromXContent(p, (String) c));
map.put(StringRareTerms.NAME, (p, c) -> ParsedStringRareTerms.fromXContent(p, (String) c));
map.put(MissingAggregationBuilder.NAME, (p, c) -> ParsedMissing.fromXContent(p, (String) c));
map.put(NestedAggregationBuilder.NAME, (p, c) -> ParsedNested.fromXContent(p, (String) c));
map.put(ReverseNestedAggregationBuilder.NAME, (p, c) -> ParsedReverseNested.fromXContent(p, (String) c));
@@ -142,10 +149,15 @@ public class NamedXContents {
map.put(GeoDistanceAggregationBuilder.NAME, (p, c) -> ParsedGeoDistance.fromXContent(p, (String) c));
map.put(FiltersAggregationBuilder.NAME, (p, c) -> ParsedFilters.fromXContent(p, (String) c));
map.put(AdjacencyMatrixAggregationBuilder.NAME, (p, c) -> ParsedAdjacencyMatrix.fromXContent(p, (String) c));
map.put(SignificantLongTerms.NAME, (p, c) -> ParsedSignificantLongTerms.fromXContent(p, (String) c));
map.put(SignificantStringTerms.NAME, (p, c) -> ParsedSignificantStringTerms.fromXContent(p, (String) c));
map.put(ScriptedMetricAggregationBuilder.NAME, (p, c) -> ParsedScriptedMetric.fromXContent(p, (String) c));
map.put(IpRangeAggregationBuilder.NAME, (p, c) -> ParsedBinaryRange.fromXContent(p, (String) c));
map.put(TopHitsAggregationBuilder.NAME, (p, c) -> ParsedTopHits.fromXContent(p, (String) c));
map.put(CompositeAggregationBuilder.NAME, (p, c) -> ParsedComposite.fromXContent(p, (String) c));
map.put(StringStatsAggregationBuilder.NAME, (p, c) -> ParsedStringStats.PARSER.parse(p, (String) c));
map.put(TopMetricsAggregationBuilder.NAME, (p, c) -> ParsedTopMetrics.PARSER.parse(p, (String) c));
map.put(InferencePipelineAggregationBuilder.NAME, (p, c) -> ParsedInference.fromXContent(p, (String) (c)));
List<NamedXContentRegistry.Entry> entries = map.entrySet().stream().map(
entry -> new NamedXContentRegistry.Entry(Aggregation.class, new ParseField(entry.getKey()), entry.getValue()))
.collect(Collectors.toList());
@@ -15,10 +15,14 @@
*/
package org.springframework.data.elasticsearch.core.join;
import java.util.Objects;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.lang.Nullable;
/**
* @author Subhobrata Dey
* @author Sascha Woo
* @since 4.1
*/
public class JoinField<ID> {
@@ -35,6 +39,7 @@ public class JoinField<ID> {
this(name, null);
}
@PersistenceConstructor
public JoinField(String name, @Nullable ID parent) {
this.name = name;
this.parent = parent;
@@ -52,4 +57,21 @@ public class JoinField<ID> {
public String getName() {
return name;
}
@Override
public int hashCode() {
return Objects.hash(name, parent);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof JoinField)) {
return false;
}
JoinField other = (JoinField) obj;
return Objects.equals(name, other.name) && Objects.equals(parent, other.parent);
}
}
@@ -105,7 +105,8 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue
}
protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) {
String queryString = StringQueryUtil.replacePlaceholders(this.query, parameterAccessor);
String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService())
.replacePlaceholders(this.query, parameterAccessor);
return new StringQuery(queryString);
}
@@ -47,7 +47,9 @@ public class ReactiveElasticsearchStringQuery extends AbstractReactiveElasticsea
@Override
protected StringQuery createQuery(ElasticsearchParameterAccessor parameterAccessor) {
String queryString = StringQueryUtil.replacePlaceholders(this.query, parameterAccessor);
String queryString = new StringQueryUtil(
getElasticsearchOperations().getElasticsearchConverter().getConversionService()).replacePlaceholders(this.query,
parameterAccessor);
return new StringQuery(queryString);
}
@@ -15,41 +15,59 @@
*/
package org.springframework.data.elasticsearch.repository.support;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
import org.springframework.data.elasticsearch.repository.query.ElasticsearchStringQuery;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
/**
* @author Peter-Josef Meisch
* @author Niklas Herder
*/
final public class StringQueryUtil {
private static final Pattern PARAMETER_PLACEHOLDER = Pattern.compile("\\?(\\d+)");
private static final GenericConversionService conversionService = new GenericConversionService();
{
if (!conversionService.canConvert(java.util.Date.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JavaDateConverter.INSTANCE);
}
if (ClassUtils.isPresent("org.joda.time.DateTimeZone", ElasticsearchStringQuery.class.getClassLoader())) {
if (!conversionService.canConvert(org.joda.time.ReadableInstant.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JodaDateTimeConverter.INSTANCE);
}
if (!conversionService.canConvert(org.joda.time.LocalDateTime.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE);
}
}
}
private final ConversionService conversionService;
private final GenericConversionService genericConversionService;
private StringQueryUtil() {}
public StringQueryUtil(ConversionService conversionService) {
public static String replacePlaceholders(String input, ParameterAccessor accessor) {
Assert.notNull(conversionService, "conversionService must not be null");
this.conversionService = conversionService;
genericConversionService = setupGenericConversionService();
}
private GenericConversionService setupGenericConversionService() {
GenericConversionService genericConversionService = new GenericConversionService();
if (!genericConversionService.canConvert(java.util.Date.class, String.class)) {
genericConversionService.addConverter(DateTimeConverters.JavaDateConverter.INSTANCE);
}
if (ClassUtils.isPresent("org.joda.time.DateTimeZone", ElasticsearchStringQuery.class.getClassLoader())) {
if (!genericConversionService.canConvert(org.joda.time.ReadableInstant.class, String.class)) {
genericConversionService.addConverter(DateTimeConverters.JodaDateTimeConverter.INSTANCE);
}
if (!genericConversionService.canConvert(org.joda.time.LocalDateTime.class, String.class)) {
genericConversionService.addConverter(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE);
}
}
return genericConversionService;
}
public String replacePlaceholders(String input, ParameterAccessor accessor) {
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
String result = input;
@@ -62,7 +80,7 @@ final public class StringQueryUtil {
return result;
}
private static String getParameterWithIndex(ParameterAccessor accessor, int index) {
private String getParameterWithIndex(ParameterAccessor accessor, int index) {
Object parameter = accessor.getBindableValue(index);
String parameterValue = "null";
@@ -70,20 +88,48 @@ final public class StringQueryUtil {
// noinspection ConstantConditions
if (parameter != null) {
parameterValue = convert(parameter);
}
return parameterValue;
}
private String convert(Object parameter) {
if (Collection.class.isAssignableFrom(parameter.getClass())) {
Collection<?> collectionParam = (Collection<?>) parameter;
StringBuilder sb = new StringBuilder("[");
sb.append(collectionParam.stream().map(o -> {
if (o instanceof String) {
return "\"" + convert(o) + "\"";
} else {
return convert(o);
}
}).collect(Collectors.joining(",")));
sb.append("]");
return sb.toString();
} else {
String parameterValue = "null";
if (conversionService.canConvert(parameter.getClass(), String.class)) {
String converted = conversionService.convert(parameter, String.class);
if (converted != null) {
parameterValue = converted;
}
} else if (genericConversionService.canConvert(parameter.getClass(), String.class)) {
String converted = genericConversionService.convert(parameter, String.class);
if (converted != null) {
parameterValue = converted;
}
} else {
parameterValue = parameter.toString();
}
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
return parameterValue;
}
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
return parameterValue;
}
}
+21
View File
@@ -1,6 +1,24 @@
Spring Data Elasticsearch Changelog
===================================
Changes in version 4.2.3 (2021-07-16)
-------------------------------------
* #1866 - Queries defined with `@Query` are not using registered converters for parameter conversion.
* #1858 - Collection parameters for @Query-annotated methods get escaped wrongly.
* #1846 - Missing hashCode and equals methods in JoinField.
Changes in version 4.2.2 (2021-06-22)
-------------------------------------
* #1834 - TopMetricsAggregation NamedObjectNotFoundException: unknown field [top_metrics].
Changes in version 4.1.10 (2021-06-22)
--------------------------------------
* #1843 - Pageable results and @Query annotation.
* #1834 - TopMetricsAggregation NamedObjectNotFoundException: unknown field [top_metrics].
Changes in version 4.2.1 (2021-05-14)
-------------------------------------
* #1811 - StringQuery execution crashes on return type `SearchPage<T>`.
@@ -1622,6 +1640,9 @@ Release Notes - Spring Data Elasticsearch - Version 1.0 M1 (2014-02-07)
+3 -1
View File
@@ -1,4 +1,4 @@
Spring Data Elasticsearch 4.2.1 (2021.0.1)
Spring Data Elasticsearch 4.2.3 (2021.0.3)
Copyright (c) [2013-2021] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -26,5 +26,7 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
@@ -0,0 +1,78 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.repository.query;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
public class ElasticsearchStringQueryUnitTestBase {
protected ElasticsearchConverter setupConverter() {
MappingElasticsearchConverter converter = new MappingElasticsearchConverter(
new SimpleElasticsearchMappingContext());
Collection<Converter<?, ?>> converters = new ArrayList<>();
converters.add(ElasticsearchStringQueryUnitTests.CarConverter.INSTANCE);
CustomConversions customConversions = new ElasticsearchCustomConversions(converters);
converter.setConversions(customConversions);
converter.afterPropertiesSet();
return converter;
}
static class Car {
@Nullable private String name;
@Nullable private String model;
@Nullable
public String getName() {
return name;
}
public void setName(@Nullable String name) {
this.name = name;
}
@Nullable
public String getModel() {
return model;
}
public void setModel(@Nullable String model) {
this.model = model;
}
}
enum CarConverter implements Converter<Car, String> {
INSTANCE;
@Override
public String convert(ElasticsearchStringQueryUnitTests.Car car) {
return (car.getName() != null ? car.getName() : "null") + '-'
+ (car.getModel() != null ? car.getModel() : "null");
}
}
}
@@ -16,8 +16,10 @@
package org.springframework.data.elasticsearch.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -39,9 +41,6 @@ import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
@@ -51,16 +50,16 @@ import org.springframework.lang.Nullable;
/**
* @author Christoph Strobl
* @author Peter-Josef Meisch
* @author Niklas Herder
*/
@ExtendWith(MockitoExtension.class)
public class ElasticsearchStringQueryUnitTests {
public class ElasticsearchStringQueryUnitTests extends ElasticsearchStringQueryUnitTestBase {
@Mock ElasticsearchOperations operations;
ElasticsearchConverter converter;
@BeforeEach
public void setUp() {
converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
when(operations.getElasticsearchConverter()).thenReturn(setupConverter());
}
@Test // DATAES-552
@@ -95,7 +94,42 @@ public class ElasticsearchStringQueryUnitTests {
.isEqualTo("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"hello \\\"Stranger\\\"\"}}]}}");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
@Test // #1858
@DisplayName("should only quote String query parameters")
void shouldOnlyEscapeStringQueryParameters() throws Exception {
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAge", Integer.valueOf(30));
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource()).isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'age' : 30 } } } }");
}
@Test // #1858
@DisplayName("should only quote String collection query parameters")
void shouldOnlyEscapeStringCollectionQueryParameters() throws Exception {
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAgeIn",
new ArrayList<>(Arrays.asList(30, 35, 40)));
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'age' : [30,35,40] } } } }");
}
@Test // #1858
@DisplayName("should escape Strings in collection query parameters")
void shouldEscapeStringsInCollectionsQueryParameters() throws Exception {
final List<String> another_string = Arrays.asList("hello \"Stranger\"", "Another string");
List<String> params = new ArrayList<>(another_string);
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByNameIn", params);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource()).isEqualTo(
"{ 'bool' : { 'must' : { 'terms' : { 'name' : [\"hello \\\"Stranger\\\"\",\"Another string\"] } } } }");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
throws NoSuchMethodException {
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
@@ -103,6 +137,22 @@ public class ElasticsearchStringQueryUnitTests {
ElasticsearchStringQuery elasticsearchStringQuery = queryForMethod(queryMethod);
return elasticsearchStringQuery.createQuery(new ElasticsearchParametersParameterAccessor(queryMethod, args));
}
@Test // #1866
@DisplayName("should use converter on parameters")
void shouldUseConverterOnParameters() throws NoSuchMethodException {
Car car = new Car();
car.setName("Toyota");
car.setModel("Prius");
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByCar", car);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'car' : 'Toyota-Prius' } } } }");
}
private ElasticsearchStringQuery queryForMethod(ElasticsearchQueryMethod queryMethod) {
return new ElasticsearchStringQuery(queryMethod, operations, queryMethod.getAnnotatedQuery());
}
@@ -111,36 +161,59 @@ public class ElasticsearchStringQueryUnitTests {
Method method = SampleRepository.class.getMethod(name, parameters);
return new ElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
new SpelAwareProxyProjectionFactory(), operations.getElasticsearchConverter().getMappingContext());
}
private interface SampleRepository extends Repository<Person, String> {
@Query("{ 'bool' : { 'must' : { 'term' : { 'age' : ?0 } } } }")
List<Person> findByAge(Integer age);
@Query("{ 'bool' : { 'must' : { 'term' : { 'age' : ?0 } } } }")
List<Person> findByAgeIn(ArrayList<Integer> age);
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
Person findByName(String name);
@Query("{ 'bool' : { 'must' : { 'terms' : { 'name' : ?0 } } } }")
Person findByNameIn(ArrayList<String> names);
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
@Query("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"?0\"}}]}}")
SearchHits<Book> findByPrefix(String prefix);
@Query("{ 'bool' : { 'must' : { 'term' : { 'car' : '?0' } } } }")
Person findByCar(Car car);
}
/**
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Artur Konczak
* @author Niklas Herder
*/
@Document(indexName = "test-index-person-query-unittest")
static class Person {
@Nullable public int age;
@Nullable @Id private String id;
@Nullable private String name;
@Nullable @Field(type = FieldType.Nested) private List<Car> car;
@Nullable @Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
@Nullable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Nullable
public String getId() {
return id;
@@ -234,29 +307,6 @@ public class ElasticsearchStringQueryUnitTests {
}
}
static class Car {
@Nullable private String name;
@Nullable private String model;
@Nullable
public String getName() {
return name;
}
public void setName(@Nullable String name) {
this.name = name;
}
@Nullable
public String getModel() {
return model;
}
public void setModel(@Nullable String model) {
this.model = model;
}
}
static class Author {
@Nullable private String id;
@@ -280,5 +330,4 @@ public class ElasticsearchStringQueryUnitTests {
this.name = name;
}
}
}
@@ -16,6 +16,7 @@
package org.springframework.data.elasticsearch.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -43,9 +44,6 @@ import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
@@ -59,16 +57,15 @@ import org.springframework.lang.Nullable;
* @author Peter-Josef Meisch
*/
@ExtendWith(MockitoExtension.class)
public class ReactiveElasticsearchStringQueryUnitTests {
public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStringQueryUnitTestBase {
SpelExpressionParser PARSER = new SpelExpressionParser();
ElasticsearchConverter converter;
@Mock ReactiveElasticsearchOperations operations;
@BeforeEach
public void setUp() {
converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
when(operations.getElasticsearchConverter()).thenReturn(setupConverter());
}
@Test // DATAES-519
@@ -132,7 +129,22 @@ public class ReactiveElasticsearchStringQueryUnitTests {
.isEqualTo("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"hello \\\"Stranger\\\"\"}}]}}");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
@Test // #1866
@DisplayName("should use converter on parameters")
void shouldUseConverterOnParameters() throws Exception {
Car car = new Car();
car.setName("Toyota");
car.setModel("Prius");
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByCar", car);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'car' : 'Toyota-Prius' } } } }");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
throws NoSuchMethodException {
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
@@ -152,7 +164,7 @@ public class ReactiveElasticsearchStringQueryUnitTests {
Method method = SampleRepository.class.getMethod(name, parameters);
return new ReactiveElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
new SpelAwareProxyProjectionFactory(), operations.getElasticsearchConverter().getMappingContext());
}
private ReactiveElasticsearchStringQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
@@ -180,6 +192,9 @@ public class ReactiveElasticsearchStringQueryUnitTests {
@Query("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"?0\"}}]}}")
Flux<SearchHit<Book>> findByPrefix(String prefix);
@Query("{ 'bool' : { 'must' : { 'term' : { 'car' : '?0' } } } }")
Mono<Person> findByCar(Car car);
}
/**
@@ -292,29 +307,6 @@ public class ReactiveElasticsearchStringQueryUnitTests {
}
}
static class Car {
@Nullable private String name;
@Nullable private String model;
@Nullable
public String getName() {
return name;
}
public void setName(@Nullable String name) {
this.name = name;
}
@Nullable
public String getModel() {
return model;
}
public void setModel(@Nullable String model) {
this.model = model;
}
}
static class Author {
@Nullable private String id;