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 f5c43564c..63a686154 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 @@ -33,7 +33,6 @@ import org.bson.BsonValue; import org.bson.Document; import org.bson.conversions.Bson; import org.bson.types.ObjectId; - import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.data.domain.Example; @@ -952,9 +951,7 @@ public class QueryMapper { MongoPersistentProperty idProperty = entity.getIdProperty(); if (idProperty != null) { - - return name.equals(idProperty.getName()) || name.equals(idProperty.getFieldName()) - || name.endsWith("." + idProperty.getName()) || name.endsWith("." + idProperty.getFieldName()); + return name.equals(idProperty.getName()) || name.equals(idProperty.getFieldName()); } return DEFAULT_ID_NAMES.contains(name); @@ -1042,16 +1039,15 @@ public class QueryMapper { @Nullable private PersistentPropertyPath getPath(String pathExpression) { - try { + String rawPath = pathExpression.replaceAll("\\.\\d+", "") // + .replaceAll(POSITIONAL_OPERATOR.pattern(), ""); - String rawPath = pathExpression.replaceAll("\\.\\d+", "") // - .replaceAll(POSITIONAL_OPERATOR.pattern(), ""); - - PropertyPath path = PropertyPath.from(rawPath, entity.getTypeInformation()); + PropertyPath path = forName(rawPath); + if (path == null || isPathToJavaLangClassProperty(path)) { + return null; + } - if (isPathToJavaLangClassProperty(path)) { - return null; - } + try { PersistentPropertyPath propertyPath = mappingContext.getPersistentPropertyPath(path); @@ -1073,7 +1069,30 @@ public class QueryMapper { } return propertyPath; + } catch (InvalidPersistentPropertyPath e) { + return null; + } + } + + /** + * Querydsl happens to map id fields directly to {@literal _id} which breaks {@link PropertyPath} resolution. So if + * the first attempt fails we try to replace {@literal _id} with just {@literal id} and see if we can resolve if + * then. + * + * @param path + * @return the path or {@literal null} + */ + @Nullable + private PropertyPath forName(String path) { + + try { + return PropertyPath.from(path, entity.getTypeInformation()); } catch (PropertyReferenceException | InvalidPersistentPropertyPath e) { + + if (path.endsWith("_id")) { + return forName(path.substring(0, path.length() - 3) + "id"); + } + 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 d0b958880..e399e399f 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 @@ -831,6 +831,30 @@ public class QueryMapperUnitTests { assertThat(document).isEqualTo(new org.bson.Document("nested.id", idHex)); } + @Test // DATAMONGO-2221 + public void shouldNotConvertHexStringToObjectIdForRenamedDeeplyNestedIdField() { + + String idHex = new ObjectId().toHexString(); + Query query = new Query(where("nested.deeplyNested.id").is(idHex)); + + org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(RootForClassWithExplicitlyRenamedIdField.class)); + + assertThat(document).isEqualTo(new org.bson.Document("nested.deeplyNested.id", idHex)); + } + + @Test // DATAMONGO-2221 + public void shouldNotConvertHexStringToObjectIdForUnresolvablePath() { + + String idHex = new ObjectId().toHexString(); + Query query = new Query(where("nested.unresolvablePath.id").is(idHex)); + + org.bson.Document document = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(RootForClassWithExplicitlyRenamedIdField.class)); + + assertThat(document).isEqualTo(new org.bson.Document("nested.unresolvablePath.id", idHex)); + } + @Document public class Foo { @Id private ObjectId id; @@ -926,6 +950,11 @@ public class QueryMapperUnitTests { static class ClassWithExplicitlyRenamedField { @Field("id") String id; + DeeplyNestedClassWithExplicitlyRenamedField deeplyNested; + } + + static class DeeplyNestedClassWithExplicitlyRenamedField { + @Field("id") String id; } static class ClassWithGeoTypes {