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 64c46749f..8d86b8899 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 @@ -1086,8 +1086,8 @@ public class QueryMapper { removePlaceholders(DOT_POSITIONAL_PATTERN, pathExpression)); if (sourceProperty != null && sourceProperty.getOwner().equals(entity)) { - return mappingContext - .getPersistentPropertyPath(PropertyPath.from(sourceProperty.getName(), entity.getTypeInformation())); + return mappingContext.getPersistentPropertyPath( + PropertyPath.from(Pattern.quote(sourceProperty.getName()), entity.getTypeInformation())); } PropertyPath path = forName(rawPath); @@ -1146,6 +1146,13 @@ public class QueryMapper { return forName(path.substring(0, path.length() - 3) + "id"); } + // Ok give it another try quoting + try { + return PropertyPath.from(Pattern.quote(path), entity.getTypeInformation()); + } catch (PropertyReferenceException | InvalidPersistentPropertyPath ex) { + + } + return null; } } 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 162693cd6..d6e325e8f 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 @@ -781,7 +781,8 @@ public class QueryMapperUnitTests { Query query = query(byExample(probe).and("listOfItems").exists(true)); org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(Foo.class)); - assertThat(document).containsEntry("embedded\\._id", "conflux").containsEntry("my_items", new org.bson.Document("$exists", true)); + assertThat(document).containsEntry("embedded\\._id", "conflux").containsEntry("my_items", + new org.bson.Document("$exists", true)); } @Test // DATAMONGO-1988 @@ -1011,6 +1012,76 @@ public class QueryMapperUnitTests { assertThat(target).isEqualTo(org.bson.Document.parse("{\"$text\" : { \"$search\" : \"test\" }}")); } + @Test // GH-3601 + void resolvesFieldnameWithUnderscoresCorrectly() { + + Query query = query(where("fieldname_with_underscores").exists(true)); + + 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))); + } + + @Test // GH-3601 + void resolvesMappedFieldnameWithUnderscoresCorrectly() { + + Query query = query(where("renamed_fieldname_with_underscores").exists(true)); + + org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(WithPropertyUsingUnderscoreInName.class)); + + assertThat(document).isEqualTo(new org.bson.Document("renamed", new org.bson.Document("$exists", true))); + } + + @Test // GH-3601 + void resolvesSimpleNestedFieldnameWithUnderscoresCorrectly() { + + Query query = query(where("simple.fieldname_with_underscores").exists(true)); + + 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))); + } + + @Test // GH-3601 + void resolvesSimpleNestedMappedFieldnameWithUnderscoresCorrectly() { + + Query query = query(where("simple.renamed_fieldname_with_underscores").exists(true)); + + org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(WrapperAroundWithPropertyUsingUnderscoreInName.class)); + + assertThat(document).isEqualTo(new org.bson.Document("simple.renamed", new org.bson.Document("$exists", true))); + } + + @Test // GH-3601 + void resolvesFieldNameWithUnderscoreOnNestedFieldnameWithUnderscoresCorrectly() { + + Query query = query(where("double_underscore.fieldname_with_underscores").exists(true)); + + 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))); + } + + @Test // GH-3601 + void resolvesFieldNameWithUnderscoreOnNestedMappedFieldnameWithUnderscoresCorrectly() { + + Query query = query(where("double_underscore.renamed_fieldname_with_underscores").exists(true)); + + 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))); + } + class WithDeepArrayNesting { List level0; @@ -1194,4 +1265,17 @@ public class QueryMapperUnitTests { this.value = value; } } + + static class WrapperAroundWithPropertyUsingUnderscoreInName { + + WithPropertyUsingUnderscoreInName simple; + WithPropertyUsingUnderscoreInName double_underscore; + } + + static class WithPropertyUsingUnderscoreInName { + + String fieldname_with_underscores; + + @Field("renamed") String renamed_fieldname_with_underscores; + } }