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 64660d2ad..f4995409c 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 abstract class AbstractRangePropertyValueConverter extends AbstractPro 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 32989a015..9c93f5259 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 4f9df40c6..3e896258a 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 @@ import org.springframework.data.mapping.PersistentProperty; */ 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 d1cdaa154..ce9ae6d2e 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 f63b734d4..f6753cc51 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.ArrayList; 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.FieldNamingStrategy; 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 @@ public class SimpleElasticsearchPersistentProperty extends 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 @@ public class SimpleElasticsearchPersistentProperty extends 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 @@ public class SimpleElasticsearchPersistentProperty extends 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 @@ public class SimpleElasticsearchPersistentProperty extends 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 89c5222d6..113c96d1d 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 @@ -961,19 +961,57 @@ public class MappingElasticsearchConverterUnitTests { @Nested class RangeTests { - static final String JSON = "{" - + "\"_class\":\"org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$RangeTests$RangeEntity\"," - + "\"integerRange\":{\"gt\":\"1\",\"lt\":\"10\"}," // - + "\"floatRange\":{\"gte\":\"1.2\",\"lte\":\"2.5\"}," // - + "\"longRange\":{\"gt\":\"2\",\"lte\":\"5\"}," // - + "\"doubleRange\":{\"gte\":\"3.2\",\"lt\":\"7.4\"}," // - + "\"dateRange\":{\"gte\":\"1970-01-01T00:00:00.000Z\",\"lte\":\"1970-01-01T01:00:00.000Z\"}," // - + "\"localDateRange\":{\"gte\":\"2021-07-06\"}," // - + "\"localTimeRange\":{\"gte\":\"00:30:00.000\",\"lt\":\"02:30:00.000\"}," // - + "\"localDateTimeRange\":{\"gt\":\"2021-01-01T00:30:00.000\",\"lt\":\"2021-01-01T02:30:00.000\"}," // - + "\"offsetTimeRange\":{\"gte\":\"00:30:00.000+02:00\",\"lt\":\"02:30:00.000+02:00\"}," // - + "\"zonedDateTimeRange\":{\"gte\":\"2021-01-01T00:30:00.000+02:00\",\"lte\":\"2021-01-01T00:30:00.000+02:00\"}," // - + "\"nullRange\":null}"; + static final String JSON = """ + { + "_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$RangeTests$RangeEntity", + "integerRange": { + "gt": "1", + "lt": "10" + }, + "floatRange": { + "gte": "1.2", + "lte": "2.5" + }, + "longRange": { + "gt": "2", + "lte": "5" + }, + "doubleRange": { + "gte": "3.2", + "lt": "7.4" + }, + "dateRange": { + "gte": "1970-01-01T00:00:00.000Z", + "lte": "1970-01-01T01:00:00.000Z" + }, + "localDateRange": { + "gte": "2021-07-06" + }, + "localTimeRange": { + "gte": "00:30:00.000", + "lt": "02:30:00.000" + }, + "localDateTimeRange": { + "gt": "2021-01-01T00:30:00.000", + "lt": "2021-01-01T02:30:00.000" + }, + "offsetTimeRange": { + "gte": "00:30:00.000+02:00", + "lt": "02:30:00.000+02:00" + }, + "zonedDateTimeRange": { + "gte": "2021-01-01T00:30:00.000+02:00", + "lte": "2021-01-01T00:30:00.000+02:00" + }, + "nullRange": null, + "integerRangeList": [ + { + "gte": "2", + "lte": "5" + } + ] + } + """; @Test public void shouldReadRanges() throws JSONException { @@ -1004,6 +1042,7 @@ public class MappingElasticsearchConverterUnitTests { 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)); }); } @@ -1027,8 +1066,7 @@ public class MappingElasticsearchConverterUnitTests { entity.setZonedDateTimeRange( Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); entity.setNullRange(null); - - // when + entity.setIntegerRangeList(List.of(Range.closed(2, 5))); Document document = mappingElasticsearchConverter.mapObject(entity); // then @@ -1053,6 +1091,8 @@ public class MappingElasticsearchConverterUnitTests { @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; } @@ -1149,6 +1189,13 @@ public class MappingElasticsearchConverterUnitTests { this.nullRange = nullRange; } + public List> getIntegerRangeList() { + return integerRangeList; + } + + public void setIntegerRangeList(List> integerRangeList) { + this.integerRangeList = integerRangeList; + } } } 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 cbb53b58b..d1cc4f0d6 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 @@ public class PropertyValueConvertersUnitTests { 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)));