Fix converting of Range<?> in Lists.

Original Pull Request #2707
Closes #2706

(cherry picked from commit 3330d65edf37d3f07d50ed229002ce7a6b9b0b64)
This commit is contained in:
Peter-Josef Meisch 2023-09-23 10:43:17 +02:00
parent 026be264fe
commit d26d01bab1
7 changed files with 106 additions and 34 deletions

View File

@ -32,9 +32,19 @@ public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPro
protected static final String LTE_FIELD = "lte"; protected static final String LTE_FIELD = "lte";
protected static final String GT_FIELD = "gt"; protected static final String GT_FIELD = "gt";
protected static final String GTE_FIELD = "gte"; 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); super(property);
this.genericType = genericType;
}
public Class<?> getGenericType() {
return genericType;
} }
@Override @Override
@ -117,10 +127,6 @@ public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPro
protected abstract String format(T value); protected abstract String format(T value);
protected Class<?> getGenericType() {
return getProperty().getTypeInformation().getTypeArguments().get(0).getType();
}
protected abstract T parse(String value); protected abstract T parse(String value);
} }

View File

@ -33,9 +33,9 @@ public class DateRangePropertyValueConverter extends AbstractRangePropertyValueC
private final List<ElasticsearchDateConverter> dateConverters; private final List<ElasticsearchDateConverter> dateConverters;
public DateRangePropertyValueConverter(PersistentProperty<?> property, public DateRangePropertyValueConverter(PersistentProperty<?> property,
List<ElasticsearchDateConverter> dateConverters) { Class<?> genericType, List<ElasticsearchDateConverter> dateConverters) {
super(property); super(property, genericType);
this.dateConverters = dateConverters; this.dateConverters = dateConverters;
} }

View File

@ -23,8 +23,12 @@ import org.springframework.data.mapping.PersistentProperty;
*/ */
public class NumberRangePropertyValueConverter extends AbstractRangePropertyValueConverter<Number> { public class NumberRangePropertyValueConverter extends AbstractRangePropertyValueConverter<Number> {
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 @Override

View File

@ -34,9 +34,9 @@ public class TemporalRangePropertyValueConverter extends AbstractRangePropertyVa
private final List<ElasticsearchDateConverter> dateConverters; private final List<ElasticsearchDateConverter> dateConverters;
public TemporalRangePropertyValueConverter(PersistentProperty<?> property, public TemporalRangePropertyValueConverter(PersistentProperty<?> property,
List<ElasticsearchDateConverter> dateConverters) { Class<?> genericType, List<ElasticsearchDateConverter> dateConverters) {
super(property); super(property, genericType);
Assert.notEmpty(dateConverters, "dateConverters must not be empty."); Assert.notEmpty(dateConverters, "dateConverters must not be empty.");
this.dateConverters = dateConverters; this.dateConverters = dateConverters;

View File

@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; 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.Property;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -168,6 +170,18 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
Supplier<Class<?>> 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()) { switch (field.type()) {
case Date: case Date:
case Date_Nanos: { case Date_Nanos: {
@ -197,11 +211,11 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
Class<?> genericType = getTypeInformation().getTypeArguments().get(0).getType(); var genericType = getGenericType.get();
if (TemporalAccessor.class.isAssignableFrom(genericType)) { if (TemporalAccessor.class.isAssignableFrom(genericType)) {
propertyValueConverter = new TemporalRangePropertyValueConverter(this, dateConverters); propertyValueConverter = new TemporalRangePropertyValueConverter(this, genericType, dateConverters);
} else if (Date.class.isAssignableFrom(genericType)) { } else if (Date.class.isAssignableFrom(genericType)) {
propertyValueConverter = new DateRangePropertyValueConverter(this, dateConverters); propertyValueConverter = new DateRangePropertyValueConverter(this, genericType, dateConverters);
} else { } else {
LOGGER.warn( LOGGER.warn(
String.format("Unsupported generic type '{%s' for date range property '%s'.", genericType, getName())); String.format("Unsupported generic type '{%s' for date range property '%s'.", genericType, getName()));
@ -216,7 +230,7 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
Class<?> genericType = getTypeInformation().getTypeArguments().get(0).getType(); var genericType = getGenericType.get();
if ((field.type() == FieldType.Integer_Range && !Integer.class.isAssignableFrom(genericType)) if ((field.type() == FieldType.Integer_Range && !Integer.class.isAssignableFrom(genericType))
|| (field.type() == FieldType.Float_Range && !Float.class.isAssignableFrom(genericType)) || (field.type() == FieldType.Float_Range && !Float.class.isAssignableFrom(genericType))
|| (field.type() == FieldType.Long_Range && !Long.class.isAssignableFrom(genericType)) || (field.type() == FieldType.Long_Range && !Long.class.isAssignableFrom(genericType))
@ -226,7 +240,7 @@ public class SimpleElasticsearchPersistentProperty extends
return; return;
} }
propertyValueConverter = new NumberRangePropertyValueConverter(this); propertyValueConverter = new NumberRangePropertyValueConverter(this, genericType);
break; break;
} }
case Ip_Range: { case Ip_Range: {

View File

@ -961,19 +961,57 @@ public class MappingElasticsearchConverterUnitTests {
@Nested @Nested
class RangeTests { class RangeTests {
static final String JSON = "{" static final String JSON = """
+ "\"_class\":\"org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$RangeTests$RangeEntity\"," {
+ "\"integerRange\":{\"gt\":\"1\",\"lt\":\"10\"}," // "_class": "org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverterUnitTests$RangeTests$RangeEntity",
+ "\"floatRange\":{\"gte\":\"1.2\",\"lte\":\"2.5\"}," // "integerRange": {
+ "\"longRange\":{\"gt\":\"2\",\"lte\":\"5\"}," // "gt": "1",
+ "\"doubleRange\":{\"gte\":\"3.2\",\"lt\":\"7.4\"}," // "lt": "10"
+ "\"dateRange\":{\"gte\":\"1970-01-01T00:00:00.000Z\",\"lte\":\"1970-01-01T01:00:00.000Z\"}," // },
+ "\"localDateRange\":{\"gte\":\"2021-07-06\"}," // "floatRange": {
+ "\"localTimeRange\":{\"gte\":\"00:30:00.000\",\"lt\":\"02:30:00.000\"}," // "gte": "1.2",
+ "\"localDateTimeRange\":{\"gt\":\"2021-01-01T00:30:00.000\",\"lt\":\"2021-01-01T02:30:00.000\"}," // "lte": "2.5"
+ "\"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\"}," // "longRange": {
+ "\"nullRange\":null}"; "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 @Test
public void shouldReadRanges() throws JSONException { public void shouldReadRanges() throws JSONException {
@ -1004,6 +1042,7 @@ public class MappingElasticsearchConverterUnitTests {
assertThat(e.getZonedDateTimeRange()).isEqualTo( assertThat(e.getZonedDateTimeRange()).isEqualTo(
Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2))));
assertThat(e.getNullRange()).isNull(); assertThat(e.getNullRange()).isNull();
assertThat(e.getIntegerRangeList()).containsExactly(Range.closed(2, 5));
}); });
} }
@ -1027,8 +1066,7 @@ public class MappingElasticsearchConverterUnitTests {
entity.setZonedDateTimeRange( entity.setZonedDateTimeRange(
Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2)))); Range.just(ZonedDateTime.of(LocalDate.of(2021, 1, 1), LocalTime.of(0, 30), ZoneOffset.ofHours(2))));
entity.setNullRange(null); entity.setNullRange(null);
entity.setIntegerRangeList(List.of(Range.closed(2, 5)));
// when
Document document = mappingElasticsearchConverter.mapObject(entity); Document document = mappingElasticsearchConverter.mapObject(entity);
// then // then
@ -1053,6 +1091,8 @@ public class MappingElasticsearchConverterUnitTests {
@Field(type = FieldType.Date_Range) private Range<ZonedDateTime> zonedDateTimeRange; @Field(type = FieldType.Date_Range) private Range<ZonedDateTime> zonedDateTimeRange;
@Field(type = FieldType.Date_Range, storeNullValue = true) private Range<ZonedDateTime> nullRange; @Field(type = FieldType.Date_Range, storeNullValue = true) private Range<ZonedDateTime> nullRange;
@Field(type = FieldType.Integer_Range) private List<Range<Integer>> integerRangeList;
public String getId() { public String getId() {
return id; return id;
} }
@ -1149,6 +1189,13 @@ public class MappingElasticsearchConverterUnitTests {
this.nullRange = nullRange; this.nullRange = nullRange;
} }
public List<Range<Integer>> getIntegerRangeList() {
return integerRangeList;
}
public void setIntegerRangeList(List<Range<Integer>> integerRangeList) {
this.integerRangeList = integerRangeList;
}
} }
} }

View File

@ -63,13 +63,14 @@ public class PropertyValueConvertersUnitTests {
converters.add(new DatePropertyValueConverter(persistentProperty, converters.add(new DatePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
Class<?> genericType = Object.class;
converters.add(new DateRangePropertyValueConverter(persistentProperty, converters.add(new DateRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); genericType, Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new NumberRangePropertyValueConverter(persistentProperty)); converters.add(new NumberRangePropertyValueConverter(persistentProperty, genericType));
converters.add(new TemporalPropertyValueConverter(persistentProperty, converters.add(new TemporalPropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date)))); Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new TemporalRangePropertyValueConverter(persistentProperty, 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( return converters.stream().map(propertyValueConverter -> arguments(
Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter))); Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter)));