From a56272e51bd5505f971b29a570eb5afd7554b550 Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Fri, 22 Sep 2023 13:29:28 +0200 Subject: [PATCH] Fix converting of Range in Lists. Closes #2706 --- .../AbstractRangePropertyValueConverter.java | 16 +++++++++---- .../DateRangePropertyValueConverter.java | 4 ++-- .../NumberRangePropertyValueConverter.java | 8 +++++-- .../TemporalRangePropertyValueConverter.java | 4 ++-- ...SimpleElasticsearchPersistentProperty.java | 24 +++++++++++++++---- ...appingElasticsearchConverterUnitTests.java | 23 +++++++++++++++--- .../PropertyValueConvertersUnitTests.java | 7 +++--- 7 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePropertyValueConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePropertyValueConverter.java index 64660d2ad5..f4995409ce 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePropertyValueConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/AbstractRangePropertyValueConverter.java @@ -32,9 +32,19 @@ public abstract class AbstractRangePropertyValueConverter extends AbstractPro protected static final String LTE_FIELD = "lte"; protected static final String GT_FIELD = "gt"; protected static final String GTE_FIELD = "gte"; + private final Class genericType; - public AbstractRangePropertyValueConverter(PersistentProperty property) { + /** + * @param property the property this convertrer belongs to + * @param genericType the generic type of the Range + */ + public AbstractRangePropertyValueConverter(PersistentProperty property, Class genericType) { super(property); + this.genericType = genericType; + } + + public Class getGenericType() { + return genericType; } @Override @@ -117,10 +127,6 @@ public Object write(Object value) { protected abstract String format(T value); - protected Class getGenericType() { - return getProperty().getTypeInformation().getTypeArguments().get(0).getType(); - } - protected abstract T parse(String value); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/DateRangePropertyValueConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/DateRangePropertyValueConverter.java index 32989a015d..9c93f5259a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/DateRangePropertyValueConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/DateRangePropertyValueConverter.java @@ -33,9 +33,9 @@ public class DateRangePropertyValueConverter extends AbstractRangePropertyValueC private final List dateConverters; public DateRangePropertyValueConverter(PersistentProperty property, - List dateConverters) { + Class genericType, List dateConverters) { - super(property); + super(property, genericType); this.dateConverters = dateConverters; } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/NumberRangePropertyValueConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/NumberRangePropertyValueConverter.java index 4f9df40c69..3e896258ab 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/NumberRangePropertyValueConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/NumberRangePropertyValueConverter.java @@ -23,8 +23,12 @@ */ public class NumberRangePropertyValueConverter extends AbstractRangePropertyValueConverter { - public NumberRangePropertyValueConverter(PersistentProperty property) { - super(property); + /** + * @param property the property this convertrer belongs to + * @param genericType the generic type of the Range + */ + public NumberRangePropertyValueConverter(PersistentProperty property, Class genericType) { + super(property, genericType); } @Override diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalRangePropertyValueConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalRangePropertyValueConverter.java index d1cdaa154d..ce9ae6d2e8 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalRangePropertyValueConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/TemporalRangePropertyValueConverter.java @@ -34,9 +34,9 @@ public class TemporalRangePropertyValueConverter extends AbstractRangePropertyVa private final List dateConverters; public TemporalRangePropertyValueConverter(PersistentProperty property, - List dateConverters) { + Class genericType, List dateConverters) { - super(property); + super(property, genericType); Assert.notEmpty(dateConverters, "dateConverters must not be empty."); this.dateConverters = dateConverters; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java index 2533677e46..4d7d0143af 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.function.Supplier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,6 +57,7 @@ import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; @@ -168,6 +170,18 @@ private void initPropertyValueConverter() { return; } + Supplier> getGenericType = () -> { + TypeInformation typeInformation = getTypeInformation(); + + if (typeInformation.isCollectionLike()) { + // we have a collection of Range + typeInformation = typeInformation.getComponentType(); + } + + Class genericType = typeInformation.getTypeArguments().get(0).getType(); + return genericType; + }; + switch (field.type()) { case Date: case Date_Nanos: { @@ -197,11 +211,11 @@ private void initPropertyValueConverter() { return; } - Class genericType = getTypeInformation().getTypeArguments().get(0).getType(); + var genericType = getGenericType.get(); if (TemporalAccessor.class.isAssignableFrom(genericType)) { - propertyValueConverter = new TemporalRangePropertyValueConverter(this, dateConverters); + propertyValueConverter = new TemporalRangePropertyValueConverter(this, genericType, dateConverters); } else if (Date.class.isAssignableFrom(genericType)) { - propertyValueConverter = new DateRangePropertyValueConverter(this, dateConverters); + propertyValueConverter = new DateRangePropertyValueConverter(this, genericType, dateConverters); } else { LOGGER.warn( String.format("Unsupported generic type '{%s' for date range property '%s'.", genericType, getName())); @@ -216,7 +230,7 @@ private void initPropertyValueConverter() { return; } - Class genericType = getTypeInformation().getTypeArguments().get(0).getType(); + var genericType = getGenericType.get(); if ((field.type() == FieldType.Integer_Range && !Integer.class.isAssignableFrom(genericType)) || (field.type() == FieldType.Float_Range && !Float.class.isAssignableFrom(genericType)) || (field.type() == FieldType.Long_Range && !Long.class.isAssignableFrom(genericType)) @@ -226,7 +240,7 @@ private void initPropertyValueConverter() { return; } - propertyValueConverter = new NumberRangePropertyValueConverter(this); + propertyValueConverter = new NumberRangePropertyValueConverter(this, genericType); break; } case Ip_Range: { diff --git a/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java index b0c7fe07c5..87dbbd15f8 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java @@ -990,7 +990,13 @@ class RangeTests { "gte": "2021-01-01T00:30:00.000+02:00", "lte": "2021-01-01T00:30:00.000+02:00" }, - "nullRange": null + "nullRange": null, + "integerRangeList": [ + { + "gte": "2", + "lte": "5" + } + ] } """; @@ -1020,6 +1026,7 @@ public void shouldReadRanges() throws JSONException { assertThat(e.getZonedDateTimeRange()).isEqualTo( Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); assertThat(e.getNullRange()).isNull(); + assertThat(e.getIntegerRangeList()).containsExactly(Range.closed(2, 5)); }); } @@ -1042,7 +1049,7 @@ public void shouldWriteRanges() throws JSONException { entity.setZonedDateTimeRange( Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); entity.setNullRange(null); - + entity.setIntegerRangeList(List.of(Range.closed(2, 5))); Document document = mappingElasticsearchConverter.mapObject(entity); assertThat(document).isEqualTo(source); @@ -1066,6 +1073,8 @@ class RangeEntity { @Field(type = FieldType.Date_Range) private Range zonedDateTimeRange; @Field(type = FieldType.Date_Range, storeNullValue = true) private Range nullRange; + @Field(type = FieldType.Integer_Range) private List> integerRangeList; + public String getId() { return id; } @@ -1162,6 +1171,13 @@ public void setNullRange(Range nullRange) { this.nullRange = nullRange; } + public List> getIntegerRangeList() { + return integerRangeList; + } + + public void setIntegerRangeList(List> integerRangeList) { + this.integerRangeList = integerRangeList; + } } } @@ -2055,7 +2071,8 @@ void shouldReadEntityWithDottedFieldName() { void shouldMapPropertyPathToFieldNames() { var propertyPath = "level1Entries.level2Entries.keyWord"; - ElasticsearchPersistentEntity persistentEntity = mappingElasticsearchConverter.getMappingContext().getPersistentEntity(NestedEntity.class); + ElasticsearchPersistentEntity persistentEntity = mappingElasticsearchConverter.getMappingContext() + .getPersistentEntity(NestedEntity.class); var mappedNames = mappingElasticsearchConverter.updateFieldNames(propertyPath, persistentEntity); assertThat(mappedNames).isEqualTo("level-one.level-two.key-word"); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/convert/PropertyValueConvertersUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/convert/PropertyValueConvertersUnitTests.java index cbb53b58b5..d1cc4f0d61 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/convert/PropertyValueConvertersUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/convert/PropertyValueConvertersUnitTests.java @@ -63,13 +63,14 @@ static Stream propertyValueConverters() { converters.add(new DatePropertyValueConverter(persistentProperty, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); + Class genericType = Object.class; converters.add(new DateRangePropertyValueConverter(persistentProperty, - Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); - converters.add(new NumberRangePropertyValueConverter(persistentProperty)); + genericType, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); + converters.add(new NumberRangePropertyValueConverter(persistentProperty, genericType)); converters.add(new TemporalPropertyValueConverter(persistentProperty, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); converters.add(new TemporalRangePropertyValueConverter(persistentProperty, - Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); + genericType, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); return converters.stream().map(propertyValueConverter -> arguments( Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter)));