Skip to content

Commit 083a38e

Browse files
committed
Fix IndexOutOfBoundsException when try to map inner hits with no results returned.
Original Pull Request #1998 Closes #1997 Co-authored-by: Peter-Josef Meisch <[email protected]> (cherry picked from commit 49324a3)
1 parent 4f3aa52 commit 083a38e

File tree

6 files changed

+114
-11
lines changed

6 files changed

+114
-11
lines changed

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePropertyValueConverter.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ public Object read(Object value) {
7676
public Object write(Object value) {
7777

7878
Assert.notNull(value, "value must not be null.");
79-
Assert.isInstanceOf(Range.class, value, "value must be instance of Range.");
79+
80+
if (!Range.class.isAssignableFrom(value.getClass())) {
81+
return value.toString();
82+
}
8083

8184
try {
8285
Range<T> range = (Range<T>) value;

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/DatePropertyValueConverter.java

+4
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ public Object read(Object value) {
5858
@Override
5959
public Object write(Object value) {
6060

61+
if (!Date.class.isAssignableFrom(value.getClass())) {
62+
return value.toString();
63+
}
64+
6165
try {
6266
return dateConverters.get(0).format((Date) value);
6367
} catch (Exception e) {

Diff for: src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalPropertyValueConverter.java

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public Object read(Object value) {
6161
@Override
6262
public Object write(Object value) {
6363

64+
if (!TemporalAccessor.class.isAssignableFrom(value.getClass())) {
65+
return value.toString();
66+
}
67+
6468
try {
6569
return dateConverters.get(0).format((TemporalAccessor) value);
6670
} catch (Exception e) {

Diff for: src/main/java/org/springframework/data/elasticsearch/core/mapping/PropertyValueConverter.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
public interface PropertyValueConverter {
2525

2626
/**
27-
* Converts a property value to an elasticsearch value.
27+
* Converts a property value to an elasticsearch value. If the converter cannot convert the value, it must return a
28+
* String representation.
2829
*
2930
* @param value the value to convert, must not be {@literal null}
3031
* @return The elasticsearch property value, must not be {@literal null}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2021 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+
package org.springframework.data.elasticsearch.core.convert;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
import static org.junit.jupiter.params.provider.Arguments.*;
20+
21+
import java.util.ArrayList;
22+
import java.util.Collections;
23+
import java.util.List;
24+
import java.util.stream.Stream;
25+
26+
import org.junit.jupiter.api.DisplayName;
27+
import org.junit.jupiter.api.Named;
28+
import org.junit.jupiter.params.ParameterizedTest;
29+
import org.junit.jupiter.params.provider.Arguments;
30+
import org.junit.jupiter.params.provider.MethodSource;
31+
import org.springframework.data.elasticsearch.annotations.DateFormat;
32+
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
33+
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
34+
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
35+
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentEntity;
36+
import org.springframework.lang.Nullable;
37+
38+
/**
39+
* @author Peter-Josef Meisch
40+
*/
41+
public class PropertyValueConvertersUnitTests {
42+
43+
@ParameterizedTest(name = "{0}") // #2018
44+
@MethodSource("propertyValueConverters")
45+
@DisplayName("should return original object on write if it cannot be converted")
46+
void shouldReturnOriginalObjectOnWriteIfItCannotBeConverted(PropertyValueConverter converter) {
47+
48+
NoConverterForThisClass value = new NoConverterForThisClass();
49+
50+
Object written = converter.write(value);
51+
52+
assertThat(written).isEqualTo(value.toString());
53+
}
54+
55+
static Stream<Arguments> propertyValueConverters() {
56+
57+
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
58+
SimpleElasticsearchPersistentEntity<?> persistentEntity = context
59+
.getRequiredPersistentEntity(NoConverterForThisClass.class);
60+
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("property");
61+
62+
List<PropertyValueConverter> converters = new ArrayList<>();
63+
64+
converters.add(new DatePropertyValueConverter(persistentProperty,
65+
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
66+
converters.add(new DateRangePropertyValueConverter(persistentProperty,
67+
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
68+
converters.add(new NumberRangePropertyValueConverter(persistentProperty));
69+
converters.add(new TemporalPropertyValueConverter(persistentProperty,
70+
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
71+
converters.add(new TemporalRangePropertyValueConverter(persistentProperty,
72+
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
73+
74+
return converters.stream().map(propertyValueConverter -> arguments(
75+
Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter)));
76+
}
77+
78+
static class NoConverterForThisClass {
79+
@SuppressWarnings("unused")
80+
@Nullable Long property;
81+
}
82+
}

Diff for: src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentPropertyUnitTests.java

+18-9
Original file line numberDiff line numberDiff line change
@@ -265,23 +265,30 @@ void shouldUseValueConverterAnnotation() {
265265

266266
// region entities
267267
static class FieldNameProperty {
268-
@Nullable @Field(name = "by-name") String fieldProperty;
268+
@Nullable
269+
@Field(name = "by-name") String fieldProperty;
269270
}
270271

271272
static class FieldValueProperty {
272-
@Nullable @Field(value = "by-value") String fieldProperty;
273+
@Nullable
274+
@Field(value = "by-value") String fieldProperty;
273275
}
274276

275277
static class MultiFieldProperty {
276-
@Nullable @MultiField(mainField = @Field("mainfield"),
278+
@Nullable
279+
@MultiField(mainField = @Field("mainfield"),
277280
otherFields = { @InnerField(suffix = "suff", type = FieldType.Keyword) }) String mainfieldProperty;
278281
}
279282

280283
static class DatesProperty {
281-
@Nullable @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate localDate;
282-
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
283-
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate;
284-
@Nullable @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") List<LocalDate> localDateList;
284+
@Nullable
285+
@Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate localDate;
286+
@Nullable
287+
@Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
288+
@Nullable
289+
@Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate;
290+
@Nullable
291+
@Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") List<LocalDate> localDateList;
285292
}
286293

287294
static class SeqNoPrimaryTermProperty {
@@ -344,8 +351,10 @@ public void setWithCustomFieldName(String withCustomFieldName) {
344351

345352
private static class EntityWithCustomValueConverters {
346353
@Id private String id;
347-
@Nullable @ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter;
348-
@Nullable @ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter;
354+
@Nullable
355+
@ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter;
356+
@Nullable
357+
@ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter;
349358
}
350359

351360
private static class ClassBasedValueConverter implements PropertyValueConverter {

0 commit comments

Comments
 (0)