Fix IndexOutOfBoundsException when try to map inner hits with no results returned.

Original Pull Request #1998
Closes #1997
Co-authored-by: Peter-Josef Meisch <pj.meisch@sothawo.com>

(cherry picked from commit 49324a369af627e390f981ed6b793f0f503526c7)
This commit is contained in:
Peter-Josef Meisch 2021-12-05 08:41:47 +01:00
parent 4f3aa52958
commit 083a38ed57
No known key found for this signature in database
GPG Key ID: DE108246970C7708
6 changed files with 114 additions and 11 deletions

View File

@ -76,7 +76,10 @@ public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPro
public Object write(Object value) { public Object write(Object value) {
Assert.notNull(value, "value must not be null."); Assert.notNull(value, "value must not be null.");
Assert.isInstanceOf(Range.class, value, "value must be instance of Range.");
if (!Range.class.isAssignableFrom(value.getClass())) {
return value.toString();
}
try { try {
Range<T> range = (Range<T>) value; Range<T> range = (Range<T>) value;

View File

@ -58,6 +58,10 @@ public class DatePropertyValueConverter extends AbstractPropertyValueConverter {
@Override @Override
public Object write(Object value) { public Object write(Object value) {
if (!Date.class.isAssignableFrom(value.getClass())) {
return value.toString();
}
try { try {
return dateConverters.get(0).format((Date) value); return dateConverters.get(0).format((Date) value);
} catch (Exception e) { } catch (Exception e) {

View File

@ -61,6 +61,10 @@ public class TemporalPropertyValueConverter extends AbstractPropertyValueConvert
@Override @Override
public Object write(Object value) { public Object write(Object value) {
if (!TemporalAccessor.class.isAssignableFrom(value.getClass())) {
return value.toString();
}
try { try {
return dateConverters.get(0).format((TemporalAccessor) value); return dateConverters.get(0).format((TemporalAccessor) value);
} catch (Exception e) { } catch (Exception e) {

View File

@ -24,7 +24,8 @@ package org.springframework.data.elasticsearch.core.mapping;
public interface PropertyValueConverter { public interface PropertyValueConverter {
/** /**
* Converts a property value to an elasticsearch value. * Converts a property value to an elasticsearch value. If the converter cannot convert the value, it must return a
* String representation.
* *
* @param value the value to convert, must not be {@literal null} * @param value the value to convert, must not be {@literal null}
* @return The elasticsearch property value, must not be {@literal null} * @return The elasticsearch property value, must not be {@literal null}

View File

@ -0,0 +1,82 @@
/*
* 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.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.params.provider.Arguments.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentEntity;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
public class PropertyValueConvertersUnitTests {
@ParameterizedTest(name = "{0}") // #2018
@MethodSource("propertyValueConverters")
@DisplayName("should return original object on write if it cannot be converted")
void shouldReturnOriginalObjectOnWriteIfItCannotBeConverted(PropertyValueConverter converter) {
NoConverterForThisClass value = new NoConverterForThisClass();
Object written = converter.write(value);
assertThat(written).isEqualTo(value.toString());
}
static Stream<Arguments> propertyValueConverters() {
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
SimpleElasticsearchPersistentEntity<?> persistentEntity = context
.getRequiredPersistentEntity(NoConverterForThisClass.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("property");
List<PropertyValueConverter> converters = new ArrayList<>();
converters.add(new DatePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new DateRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new NumberRangePropertyValueConverter(persistentProperty));
converters.add(new TemporalPropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new TemporalRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
return converters.stream().map(propertyValueConverter -> arguments(
Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter)));
}
static class NoConverterForThisClass {
@SuppressWarnings("unused")
@Nullable Long property;
}
}

View File

@ -265,23 +265,30 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
// region entities // region entities
static class FieldNameProperty { static class FieldNameProperty {
@Nullable @Field(name = "by-name") String fieldProperty; @Nullable
@Field(name = "by-name") String fieldProperty;
} }
static class FieldValueProperty { static class FieldValueProperty {
@Nullable @Field(value = "by-value") String fieldProperty; @Nullable
@Field(value = "by-value") String fieldProperty;
} }
static class MultiFieldProperty { static class MultiFieldProperty {
@Nullable @MultiField(mainField = @Field("mainfield"), @Nullable
@MultiField(mainField = @Field("mainfield"),
otherFields = { @InnerField(suffix = "suff", type = FieldType.Keyword) }) String mainfieldProperty; otherFields = { @InnerField(suffix = "suff", type = FieldType.Keyword) }) String mainfieldProperty;
} }
static class DatesProperty { static class DatesProperty {
@Nullable @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate localDate; @Nullable
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime; @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate localDate;
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate; @Nullable
@Nullable @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") List<LocalDate> localDateList; @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
@Nullable
@Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate;
@Nullable
@Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") List<LocalDate> localDateList;
} }
static class SeqNoPrimaryTermProperty { static class SeqNoPrimaryTermProperty {
@ -344,8 +351,10 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
private static class EntityWithCustomValueConverters { private static class EntityWithCustomValueConverters {
@Id private String id; @Id private String id;
@Nullable @ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter; @Nullable
@Nullable @ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter; @ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter;
@Nullable
@ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter;
} }
private static class ClassBasedValueConverter implements PropertyValueConverter { private static class ClassBasedValueConverter implements PropertyValueConverter {