Skip to content

Commit ac5c724

Browse files
committed
Skip value conversion of Pattern and BsonRegularExpression in QueryMapper.
QueryMapper no longer attempts to convert regex objects when a field has an explicit write target. Closes #4649
1 parent 46afd6f commit ac5c724

File tree

2 files changed

+71
-34
lines changed

2 files changed

+71
-34
lines changed

Diff for: spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import org.apache.commons.logging.Log;
3434
import org.apache.commons.logging.LogFactory;
35+
import org.bson.BsonRegularExpression;
3536
import org.bson.BsonValue;
3637
import org.bson.Document;
3738
import org.bson.conversions.Bson;
@@ -868,15 +869,16 @@ protected boolean isKeyword(String candidate) {
868869
* conversions. In case of a {@link Collection} (used eg. for {@code $in} queries) the individual values will be
869870
* converted one by one.
870871
*
871-
* @param documentField the field and its meta data
872+
* @param documentField the field and its metadata
872873
* @param value the actual value. Can be {@literal null}.
873874
* @return the potentially converted target value.
874875
*/
875876
@Nullable
876877
private Object applyFieldTargetTypeHintToValue(Field documentField, @Nullable Object value) {
877878

878879
if (value == null || documentField.getProperty() == null || !documentField.getProperty().hasExplicitWriteTarget()
879-
|| value instanceof Document || value instanceof DBObject) {
880+
|| value instanceof Document || value instanceof DBObject || value instanceof Pattern
881+
|| value instanceof BsonRegularExpression) {
880882
return value;
881883
}
882884

Diff for: spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

+67-32
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@
2929
import java.util.Map;
3030
import java.util.Optional;
3131
import java.util.TreeMap;
32+
import java.util.regex.Pattern;
3233

34+
import org.bson.BsonRegularExpression;
3335
import org.bson.conversions.Bson;
3436
import org.bson.types.Code;
3537
import org.bson.types.ObjectId;
3638
import org.junit.jupiter.api.BeforeEach;
3739
import org.junit.jupiter.api.Test;
40+
3841
import org.springframework.core.convert.converter.Converter;
3942
import org.springframework.data.annotation.Id;
4043
import org.springframework.data.annotation.Transient;
@@ -52,8 +55,17 @@
5255
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
5356
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
5457
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
55-
import org.springframework.data.mongodb.core.mapping.*;
58+
import org.springframework.data.mongodb.core.mapping.DBRef;
59+
import org.springframework.data.mongodb.core.mapping.Document;
60+
import org.springframework.data.mongodb.core.mapping.DocumentReference;
61+
import org.springframework.data.mongodb.core.mapping.Field;
5662
import org.springframework.data.mongodb.core.mapping.FieldName.Type;
63+
import org.springframework.data.mongodb.core.mapping.FieldType;
64+
import org.springframework.data.mongodb.core.mapping.MongoId;
65+
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
66+
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
67+
import org.springframework.data.mongodb.core.mapping.TextScore;
68+
import org.springframework.data.mongodb.core.mapping.Unwrapped;
5769
import org.springframework.data.mongodb.core.query.BasicQuery;
5870
import org.springframework.data.mongodb.core.query.Criteria;
5971
import org.springframework.data.mongodb.core.query.Query;
@@ -629,7 +641,7 @@ void queryMapperShouldNotTryToMapDBRefListPropertyIfNestedInsideDocumentWithinDo
629641

630642
org.bson.Document queryObject = query(
631643
where("referenceList").is(new org.bson.Document("$nested", new org.bson.Document("$keys", 0L))))
632-
.getQueryObject();
644+
.getQueryObject();
633645

634646
org.bson.Document mappedObject = mapper.getMappedObject(queryObject,
635647
context.getPersistentEntity(WithDBRefList.class));
@@ -901,7 +913,7 @@ void mappingShouldRetainNestedNumericMapKeys() {
901913
@Test // GH-3688
902914
void mappingShouldAllowSettingEntireNestedNumericKeyedMapValue() {
903915

904-
Query query = query(where("outerMap.1.map").is(null)); //newEntityWithComplexValueTypeMap()
916+
Query query = query(where("outerMap.1.map").is(null)); // newEntityWithComplexValueTypeMap()
905917

906918
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
907919
context.getPersistentEntity(EntityWithIntKeyedMapOfMap.class));
@@ -1073,6 +1085,22 @@ void shouldConvertCollectionPropertyWithExplicitTargetType() {
10731085
assertThat(document).isEqualTo(new org.bson.Document("scripts", new Code(script)));
10741086
}
10751087

1088+
@Test // GH-4649
1089+
void shouldRetainRegexPattern() {
1090+
1091+
Query query = new Query(where("text").regex("foo"));
1092+
1093+
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
1094+
context.getPersistentEntity(WithExplicitTargetTypes.class));
1095+
1096+
assertThat(document.get("text")).isInstanceOf(Pattern.class);
1097+
1098+
query = new Query(where("text").regex(new BsonRegularExpression("foo")));
1099+
document = mapper.getMappedObject(query.getQueryObject(),
1100+
context.getPersistentEntity(WithExplicitTargetTypes.class));
1101+
assertThat(document.get("text")).isInstanceOf(BsonRegularExpression.class);
1102+
}
1103+
10761104
@Test // DATAMONGO-2339
10771105
void findByIdUsesMappedIdFieldNameWithUnderscoreCorrectly() {
10781106

@@ -1376,7 +1404,8 @@ void resolvesFieldnameWithUnderscoresCorrectly() {
13761404
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
13771405
context.getPersistentEntity(WithPropertyUsingUnderscoreInName.class));
13781406

1379-
assertThat(document).isEqualTo(new org.bson.Document("fieldname_with_underscores", new org.bson.Document("$exists", true)));
1407+
assertThat(document)
1408+
.isEqualTo(new org.bson.Document("fieldname_with_underscores", new org.bson.Document("$exists", true)));
13801409
}
13811410

13821411
@Test // GH-3601
@@ -1398,7 +1427,8 @@ void resolvesSimpleNestedFieldnameWithUnderscoresCorrectly() {
13981427
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
13991428
context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class));
14001429

1401-
assertThat(document).isEqualTo(new org.bson.Document("simple.fieldname_with_underscores", new org.bson.Document("$exists", true)));
1430+
assertThat(document)
1431+
.isEqualTo(new org.bson.Document("simple.fieldname_with_underscores", new org.bson.Document("$exists", true)));
14021432
}
14031433

14041434
@Test // GH-3601
@@ -1420,7 +1450,8 @@ void resolvesFieldNameWithUnderscoreOnNestedFieldnameWithUnderscoresCorrectly()
14201450
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
14211451
context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class));
14221452

1423-
assertThat(document).isEqualTo(new org.bson.Document("double_underscore.fieldname_with_underscores", new org.bson.Document("$exists", true)));
1453+
assertThat(document).isEqualTo(
1454+
new org.bson.Document("double_underscore.fieldname_with_underscores", new org.bson.Document("$exists", true)));
14241455
}
14251456

14261457
@Test // GH-3601
@@ -1431,7 +1462,8 @@ void resolvesFieldNameWithUnderscoreOnNestedMappedFieldnameWithUnderscoresCorrec
14311462
org.bson.Document document = mapper.getMappedObject(query.getQueryObject(),
14321463
context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class));
14331464

1434-
assertThat(document).isEqualTo(new org.bson.Document("double_underscore.renamed", new org.bson.Document("$exists", true)));
1465+
assertThat(document)
1466+
.isEqualTo(new org.bson.Document("double_underscore.renamed", new org.bson.Document("$exists", true)));
14351467
}
14361468

14371469
@Test // GH-3633
@@ -1469,7 +1501,8 @@ void allowsUsingFieldPathsForPropertiesHavingCustomConversionRegistered() {
14691501

14701502
Query query = query(where("address.street").is("1007 Mountain Drive"));
14711503

1472-
MongoCustomConversions mongoCustomConversions = new MongoCustomConversions(Collections.singletonList(new MyAddressToDocumentConverter()));
1504+
MongoCustomConversions mongoCustomConversions = new MongoCustomConversions(
1505+
Collections.singletonList(new MyAddressToDocumentConverter()));
14731506

14741507
this.context = new MongoMappingContext();
14751508
this.context.setSimpleTypeHolder(mongoCustomConversions.getSimpleTypeHolder());
@@ -1481,7 +1514,8 @@ void allowsUsingFieldPathsForPropertiesHavingCustomConversionRegistered() {
14811514

14821515
this.mapper = new QueryMapper(converter);
14831516

1484-
assertThat(mapper.getMappedSort(query.getQueryObject(), context.getPersistentEntity(Customer.class))).isEqualTo(new org.bson.Document("address.street", "1007 Mountain Drive"));
1517+
assertThat(mapper.getMappedSort(query.getQueryObject(), context.getPersistentEntity(Customer.class)))
1518+
.isEqualTo(new org.bson.Document("address.street", "1007 Mountain Drive"));
14851519
}
14861520

14871521
@Test // GH-3790
@@ -1502,7 +1536,8 @@ void shouldAcceptExprAsCriteriaDefinition() {
15021536
@Test // GH-3668
15031537
void mapStringIdFieldProjection() {
15041538

1505-
org.bson.Document mappedFields = mapper.getMappedFields(new org.bson.Document("id", 1), context.getPersistentEntity(WithStringId.class));
1539+
org.bson.Document mappedFields = mapper.getMappedFields(new org.bson.Document("id", 1),
1540+
context.getPersistentEntity(WithStringId.class));
15061541
assertThat(mappedFields).containsEntry("_id", 1);
15071542
}
15081543

@@ -1528,7 +1563,8 @@ void mapStringIdFieldProjection() {
15281563
@Test // GH-3596
15291564
void considersValueConverterWhenPresent() {
15301565

1531-
org.bson.Document mappedObject = mapper.getMappedObject(new org.bson.Document("text", "value"), context.getPersistentEntity(WithPropertyValueConverter.class));
1566+
org.bson.Document mappedObject = mapper.getMappedObject(new org.bson.Document("text", "value"),
1567+
context.getPersistentEntity(WithPropertyValueConverter.class));
15321568
assertThat(mappedObject).isEqualTo(new org.bson.Document("text", "eulav"));
15331569
}
15341570

@@ -1589,7 +1625,8 @@ void convertsListOfValuesForPropertyThatHasValueConverterButIsNotCollectionLikeO
15891625
@Test // GH-4464
15901626
void usesKeyNameWithDotsIfFieldNameTypeIsKey() {
15911627

1592-
org.bson.Document mappedObject = mapper.getMappedObject(query(where("value").is("A")).getQueryObject(), context.getPersistentEntity(WithPropertyHavingDotsInFieldName.class));
1628+
org.bson.Document mappedObject = mapper.getMappedObject(query(where("value").is("A")).getQueryObject(),
1629+
context.getPersistentEntity(WithPropertyHavingDotsInFieldName.class));
15931630
assertThat(mappedObject).isEqualTo("{ 'field.name.with.dots' : 'A' }");
15941631
}
15951632

@@ -1606,7 +1643,8 @@ void mappingShouldRetainMapKeyOrder() {
16061643
@Test // GH-4510
16071644
void convertsNestedOperatorValueForPropertyThatHasValueConverter() {
16081645

1609-
org.bson.Document mappedObject = mapper.getMappedObject(query(where("text").gt("spring").lt( "data")).getQueryObject(),
1646+
org.bson.Document mappedObject = mapper.getMappedObject(
1647+
query(where("text").gt("spring").lt("data")).getQueryObject(),
16101648
context.getPersistentEntity(WithPropertyValueConverter.class));
16111649

16121650
assertThat(mappedObject).isEqualTo("{ 'text' : { $gt : 'gnirps', $lt : 'atad' } }");
@@ -1615,7 +1653,8 @@ void convertsNestedOperatorValueForPropertyThatHasValueConverter() {
16151653
@Test // GH-4510
16161654
void convertsNestedOperatorValueForPropertyContainingListThatHasValueConverter() {
16171655

1618-
org.bson.Document mappedObject = mapper.getMappedObject(query(where("text").gt("spring").in( "data")).getQueryObject(),
1656+
org.bson.Document mappedObject = mapper.getMappedObject(
1657+
query(where("text").gt("spring").in("data")).getQueryObject(),
16191658
context.getPersistentEntity(WithPropertyValueConverter.class));
16201659

16211660
assertThat(mappedObject).isEqualTo("{ 'text' : { $gt : 'gnirps', $in : [ 'atad' ] } }");
@@ -1752,23 +1791,20 @@ static class WithDocumentReference {
17521791

17531792
private String name;
17541793

1755-
@DocumentReference(lookup = "{ 'name' : ?#{#target} }")
1756-
private Customer customer;
1794+
@DocumentReference(lookup = "{ 'name' : ?#{#target} }") private Customer customer;
17571795

1758-
@DocumentReference(lookup = "{ 'name' : ?#{#target} }")
1759-
private List<Customer> customers;
1796+
@DocumentReference(lookup = "{ 'name' : ?#{#target} }") private List<Customer> customers;
17601797

1761-
@DocumentReference
1762-
private Sample sample;
1798+
@DocumentReference private Sample sample;
17631799

1764-
@DocumentReference
1765-
private List<Sample> samples;
1800+
@DocumentReference private List<Sample> samples;
17661801
}
17671802

17681803
class WithTextScoreProperty {
17691804

17701805
@Id String id;
1771-
@TextScore @Field("score") Float textScore;
1806+
@TextScore
1807+
@Field("score") Float textScore;
17721808
}
17731809

17741810
static class RootForClassWithExplicitlyRenamedIdField {
@@ -1805,7 +1841,7 @@ static class EntityWithComplexValueTypeMap {
18051841
Map<Integer, SimpleEntityWithoutId> map;
18061842
}
18071843

1808-
static class EntityWithIntKeyedMapOfMap{
1844+
static class EntityWithIntKeyedMapOfMap {
18091845
Map<Integer, EntityWithComplexValueTypeMap> outerMap;
18101846
}
18111847

@@ -1818,6 +1854,9 @@ static class WithExplicitTargetTypes {
18181854
@Field(targetType = FieldType.SCRIPT) //
18191855
String script;
18201856

1857+
@Field(targetType = FieldType.STRING) //
1858+
String text;
1859+
18211860
@Field(targetType = FieldType.SCRIPT) //
18221861
List<String> scripts;
18231862
}
@@ -1887,15 +1926,13 @@ static class WithPropertyUsingUnderscoreInName {
18871926

18881927
String fieldname_with_underscores;
18891928

1890-
@Field("renamed")
1891-
String renamed_fieldname_with_underscores;
1929+
@Field("renamed") String renamed_fieldname_with_underscores;
18921930
}
18931931

18941932
@Document
18951933
static class Customer {
18961934

1897-
@Id
1898-
private ObjectId id;
1935+
@Id private ObjectId id;
18991936
private String name;
19001937
private MyAddress address;
19011938
}
@@ -1906,8 +1943,7 @@ static class MyAddress {
19061943

19071944
static class WithPropertyValueConverter {
19081945

1909-
@ValueConverter(ReversingValueConverter.class)
1910-
String text;
1946+
@ValueConverter(ReversingValueConverter.class) String text;
19111947
}
19121948

19131949
@WritingConverter
@@ -1923,8 +1959,7 @@ public org.bson.Document convert(MyAddress address) {
19231959

19241960
static class WithPropertyHavingDotsInFieldName {
19251961

1926-
@Field(name = "field.name.with.dots", nameType = Type.KEY)
1927-
String value;
1962+
@Field(name = "field.name.with.dots", nameType = Type.KEY) String value;
19281963

19291964
}
19301965
}

0 commit comments

Comments
 (0)