diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 2e0362747..4257f9665 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.bson.BsonRegularExpression; import org.bson.BsonValue; import org.bson.Document; import org.bson.conversions.Bson; @@ -868,7 +869,7 @@ public class QueryMapper { * conversions. In case of a {@link Collection} (used eg. for {@code $in} queries) the individual values will be * converted one by one. * - * @param documentField the field and its meta data + * @param documentField the field and its metadata * @param value the actual value. Can be {@literal null}. * @return the potentially converted target value. */ @@ -876,7 +877,8 @@ public class QueryMapper { private Object applyFieldTargetTypeHintToValue(Field documentField, @Nullable Object value) { if (value == null || documentField.getProperty() == null || !documentField.getProperty().hasExplicitWriteTarget() - || value instanceof Document || value instanceof DBObject) { + || value instanceof Document || value instanceof DBObject || value instanceof Pattern + || value instanceof BsonRegularExpression) { return value; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index cde5e0ff6..88b469760 100755 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -29,12 +29,15 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; +import java.util.regex.Pattern; +import org.bson.BsonRegularExpression; import org.bson.conversions.Bson; import org.bson.types.Code; import org.bson.types.ObjectId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Transient; @@ -52,8 +55,17 @@ import org.springframework.data.mongodb.core.aggregation.EvaluationOperators.Exp import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.data.mongodb.core.geo.GeoJsonPolygon; -import org.springframework.data.mongodb.core.mapping.*; +import org.springframework.data.mongodb.core.mapping.DBRef; +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.FieldName.Type; +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.Criteria; import org.springframework.data.mongodb.core.query.Query; @@ -629,7 +641,7 @@ public class QueryMapperUnitTests { org.bson.Document queryObject = query( where("referenceList").is(new org.bson.Document("$nested", new org.bson.Document("$keys", 0L)))) - .getQueryObject(); + .getQueryObject(); org.bson.Document mappedObject = mapper.getMappedObject(queryObject, context.getPersistentEntity(WithDBRefList.class)); @@ -901,7 +913,7 @@ public class QueryMapperUnitTests { @Test // GH-3688 void mappingShouldAllowSettingEntireNestedNumericKeyedMapValue() { - Query query = query(where("outerMap.1.map").is(null)); //newEntityWithComplexValueTypeMap() + Query query = query(where("outerMap.1.map").is(null)); // newEntityWithComplexValueTypeMap() org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(EntityWithIntKeyedMapOfMap.class)); @@ -1073,6 +1085,22 @@ public class QueryMapperUnitTests { assertThat(document).isEqualTo(new org.bson.Document("scripts", new Code(script))); } + @Test // GH-4649 + void shouldRetainRegexPattern() { + + Query query = new Query(where("text").regex("foo")); + + org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(WithExplicitTargetTypes.class)); + + assertThat(document.get("text")).isInstanceOf(Pattern.class); + + query = new Query(where("text").regex(new BsonRegularExpression("foo"))); + document = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(WithExplicitTargetTypes.class)); + assertThat(document.get("text")).isInstanceOf(BsonRegularExpression.class); + } + @Test // DATAMONGO-2339 void findByIdUsesMappedIdFieldNameWithUnderscoreCorrectly() { @@ -1376,7 +1404,8 @@ public class QueryMapperUnitTests { org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WithPropertyUsingUnderscoreInName.class)); - assertThat(document).isEqualTo(new org.bson.Document("fieldname_with_underscores", new org.bson.Document("$exists", true))); + assertThat(document) + .isEqualTo(new org.bson.Document("fieldname_with_underscores", new org.bson.Document("$exists", true))); } @Test // GH-3601 @@ -1398,7 +1427,8 @@ public class QueryMapperUnitTests { org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class)); - assertThat(document).isEqualTo(new org.bson.Document("simple.fieldname_with_underscores", new org.bson.Document("$exists", true))); + assertThat(document) + .isEqualTo(new org.bson.Document("simple.fieldname_with_underscores", new org.bson.Document("$exists", true))); } @Test // GH-3601 @@ -1420,7 +1450,8 @@ public class QueryMapperUnitTests { org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class)); - assertThat(document).isEqualTo(new org.bson.Document("double_underscore.fieldname_with_underscores", new org.bson.Document("$exists", true))); + assertThat(document).isEqualTo( + new org.bson.Document("double_underscore.fieldname_with_underscores", new org.bson.Document("$exists", true))); } @Test // GH-3601 @@ -1431,7 +1462,8 @@ public class QueryMapperUnitTests { org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class)); - assertThat(document).isEqualTo(new org.bson.Document("double_underscore.renamed", new org.bson.Document("$exists", true))); + assertThat(document) + .isEqualTo(new org.bson.Document("double_underscore.renamed", new org.bson.Document("$exists", true))); } @Test // GH-3633 @@ -1469,7 +1501,8 @@ public class QueryMapperUnitTests { Query query = query(where("address.street").is("1007 Mountain Drive")); - MongoCustomConversions mongoCustomConversions = new MongoCustomConversions(Collections.singletonList(new MyAddressToDocumentConverter())); + MongoCustomConversions mongoCustomConversions = new MongoCustomConversions( + Collections.singletonList(new MyAddressToDocumentConverter())); this.context = new MongoMappingContext(); this.context.setSimpleTypeHolder(mongoCustomConversions.getSimpleTypeHolder()); @@ -1481,7 +1514,8 @@ public class QueryMapperUnitTests { this.mapper = new QueryMapper(converter); - assertThat(mapper.getMappedSort(query.getQueryObject(), context.getPersistentEntity(Customer.class))).isEqualTo(new org.bson.Document("address.street", "1007 Mountain Drive")); + assertThat(mapper.getMappedSort(query.getQueryObject(), context.getPersistentEntity(Customer.class))) + .isEqualTo(new org.bson.Document("address.street", "1007 Mountain Drive")); } @Test // GH-3790 @@ -1502,7 +1536,8 @@ public class QueryMapperUnitTests { @Test // GH-3668 void mapStringIdFieldProjection() { - org.bson.Document mappedFields = mapper.getMappedFields(new org.bson.Document("id", 1), context.getPersistentEntity(WithStringId.class)); + org.bson.Document mappedFields = mapper.getMappedFields(new org.bson.Document("id", 1), + context.getPersistentEntity(WithStringId.class)); assertThat(mappedFields).containsEntry("_id", 1); } @@ -1528,7 +1563,8 @@ public class QueryMapperUnitTests { @Test // GH-3596 void considersValueConverterWhenPresent() { - org.bson.Document mappedObject = mapper.getMappedObject(new org.bson.Document("text", "value"), context.getPersistentEntity(WithPropertyValueConverter.class)); + org.bson.Document mappedObject = mapper.getMappedObject(new org.bson.Document("text", "value"), + context.getPersistentEntity(WithPropertyValueConverter.class)); assertThat(mappedObject).isEqualTo(new org.bson.Document("text", "eulav")); } @@ -1589,7 +1625,8 @@ public class QueryMapperUnitTests { @Test // GH-4464 void usesKeyNameWithDotsIfFieldNameTypeIsKey() { - org.bson.Document mappedObject = mapper.getMappedObject(query(where("value").is("A")).getQueryObject(), context.getPersistentEntity(WithPropertyHavingDotsInFieldName.class)); + org.bson.Document mappedObject = mapper.getMappedObject(query(where("value").is("A")).getQueryObject(), + context.getPersistentEntity(WithPropertyHavingDotsInFieldName.class)); assertThat(mappedObject).isEqualTo("{ 'field.name.with.dots' : 'A' }"); } @@ -1606,7 +1643,8 @@ public class QueryMapperUnitTests { @Test // GH-4510 void convertsNestedOperatorValueForPropertyThatHasValueConverter() { - org.bson.Document mappedObject = mapper.getMappedObject(query(where("text").gt("spring").lt( "data")).getQueryObject(), + org.bson.Document mappedObject = mapper.getMappedObject( + query(where("text").gt("spring").lt("data")).getQueryObject(), context.getPersistentEntity(WithPropertyValueConverter.class)); assertThat(mappedObject).isEqualTo("{ 'text' : { $gt : 'gnirps', $lt : 'atad' } }"); @@ -1615,7 +1653,8 @@ public class QueryMapperUnitTests { @Test // GH-4510 void convertsNestedOperatorValueForPropertyContainingListThatHasValueConverter() { - org.bson.Document mappedObject = mapper.getMappedObject(query(where("text").gt("spring").in( "data")).getQueryObject(), + org.bson.Document mappedObject = mapper.getMappedObject( + query(where("text").gt("spring").in("data")).getQueryObject(), context.getPersistentEntity(WithPropertyValueConverter.class)); assertThat(mappedObject).isEqualTo("{ 'text' : { $gt : 'gnirps', $in : [ 'atad' ] } }"); @@ -1752,23 +1791,20 @@ public class QueryMapperUnitTests { private String name; - @DocumentReference(lookup = "{ 'name' : ?#{#target} }") - private Customer customer; + @DocumentReference(lookup = "{ 'name' : ?#{#target} }") private Customer customer; - @DocumentReference(lookup = "{ 'name' : ?#{#target} }") - private List customers; + @DocumentReference(lookup = "{ 'name' : ?#{#target} }") private List customers; - @DocumentReference - private Sample sample; + @DocumentReference private Sample sample; - @DocumentReference - private List samples; + @DocumentReference private List samples; } class WithTextScoreProperty { @Id String id; - @TextScore @Field("score") Float textScore; + @TextScore + @Field("score") Float textScore; } static class RootForClassWithExplicitlyRenamedIdField { @@ -1805,7 +1841,7 @@ public class QueryMapperUnitTests { Map map; } - static class EntityWithIntKeyedMapOfMap{ + static class EntityWithIntKeyedMapOfMap { Map outerMap; } @@ -1818,6 +1854,9 @@ public class QueryMapperUnitTests { @Field(targetType = FieldType.SCRIPT) // String script; + @Field(targetType = FieldType.STRING) // + String text; + @Field(targetType = FieldType.SCRIPT) // List scripts; } @@ -1887,15 +1926,13 @@ public class QueryMapperUnitTests { String fieldname_with_underscores; - @Field("renamed") - String renamed_fieldname_with_underscores; + @Field("renamed") String renamed_fieldname_with_underscores; } @Document static class Customer { - @Id - private ObjectId id; + @Id private ObjectId id; private String name; private MyAddress address; } @@ -1906,8 +1943,7 @@ public class QueryMapperUnitTests { static class WithPropertyValueConverter { - @ValueConverter(ReversingValueConverter.class) - String text; + @ValueConverter(ReversingValueConverter.class) String text; } @WritingConverter @@ -1923,8 +1959,7 @@ public class QueryMapperUnitTests { static class WithPropertyHavingDotsInFieldName { - @Field(name = "field.name.with.dots", nameType = Type.KEY) - String value; + @Field(name = "field.name.with.dots", nameType = Type.KEY) String value; } }