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 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<T> extends AbstractPro
protected abstract String format(T value);
protected Class<?> getGenericType() {
return getProperty().getTypeInformation().getTypeArguments().get(0).getType();
}
protected abstract T parse(String value);
}

View File

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

View File

@ -23,8 +23,12 @@ import org.springframework.data.mapping.PersistentProperty;
*/
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

View File

@ -34,9 +34,9 @@ public class TemporalRangePropertyValueConverter extends AbstractRangePropertyVa
private final List<ElasticsearchDateConverter> dateConverters;
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.");
this.dateConverters = dateConverters;

View File

@ -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<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()) {
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: {

View File

@ -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<ZonedDateTime> zonedDateTimeRange;
@Field(type = FieldType.Date_Range, storeNullValue = true) private Range<ZonedDateTime> nullRange;
@Field(type = FieldType.Integer_Range) private List<Range<Integer>> integerRangeList;
public String getId() {
return id;
}
@ -1149,6 +1189,13 @@ public class MappingElasticsearchConverterUnitTests {
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,
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)));