Browse Source

Fix property value conversion for `$in` clauses.

This commit fixes an issue where a property value converter is not applied if the query is using an $in clause that compares the value against a collection of potential candidates.

Closes #4080
Original pull request: #4324
pull/4309/merge
Christoph Strobl 3 years ago committed by Mark Paluch
parent
commit
c2f708a37a
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
  2. 20
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

22
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java

@ -30,6 +30,8 @@ import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Reference; import org.springframework.data.annotation.Reference;
import org.springframework.data.convert.PropertyValueConverter;
import org.springframework.data.convert.ValueConversionContext;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
import org.springframework.data.mapping.Association; import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.MappingException;
@ -40,6 +42,7 @@ import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mapping.context.InvalidPersistentPropertyPath; import org.springframework.data.mapping.context.InvalidPersistentPropertyPath;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mongodb.MongoExpression; import org.springframework.data.mongodb.MongoExpression;
import org.springframework.data.mongodb.core.aggregation.AggregationExpression; import org.springframework.data.mongodb.core.aggregation.AggregationExpression;
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext; import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
@ -437,9 +440,22 @@ public class QueryMapper {
if (documentField.getProperty() != null if (documentField.getProperty() != null
&& converter.getCustomConversions().hasValueConverter(documentField.getProperty())) { && converter.getCustomConversions().hasValueConverter(documentField.getProperty())) {
return converter.getCustomConversions().getPropertyValueConversions()
.getValueConverter(documentField.getProperty()) MongoConversionContext conversionContext = new MongoConversionContext(new PropertyValueProvider<>() {
.write(value, new MongoConversionContext(null, documentField.getProperty(), converter)); @Override
public <T> T getPropertyValue(MongoPersistentProperty property) {
throw new IllegalStateException("No enclosing property available");
}
}, documentField.getProperty(), converter);
PropertyValueConverter<Object, Object, ValueConversionContext<MongoPersistentProperty>> valueConverter = converter
.getCustomConversions().getPropertyValueConversions().getValueConverter(documentField.getProperty());
/* might be an $in clause with multiple entries */
if (!documentField.getProperty().isCollectionLike() && sourceValue instanceof Collection<?> collection) {
return collection.stream().map(it -> valueConverter.write(it, conversionContext)).collect(Collectors.toList());
}
return valueConverter.write(value, conversionContext);
} }
if (documentField.isIdField() && !documentField.isAssociation()) { if (documentField.isIdField() && !documentField.isAssociation()) {

20
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

@ -51,16 +51,7 @@ import org.springframework.data.mongodb.core.aggregation.EvaluationOperators.Exp
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext; import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon; import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.*;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.DocumentReference;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
@ -1509,6 +1500,15 @@ public class QueryMapperUnitTests {
assertThat(mappedObject).isEqualTo("{ $expr : { $gt : [ '$field', '$budget'] } }"); assertThat(mappedObject).isEqualTo("{ $expr : { $gt : [ '$field', '$budget'] } }");
} }
@Test // GH-4080
void convertsListOfValuesForPropertyThatHasValueConverterButIsNotCollectionLikeOneByOne() {
org.bson.Document mappedObject = mapper.getMappedObject(query(where("text").in("spring", "data")).getQueryObject(),
context.getPersistentEntity(WithPropertyValueConverter.class));
assertThat(mappedObject).isEqualTo("{ 'text' : { $in : ['gnirps', 'atad'] } }");
}
class WithDeepArrayNesting { class WithDeepArrayNesting {
List<WithNestedArray> level0; List<WithNestedArray> level0;

Loading…
Cancel
Save