DATAMONGO-2221 - Fix mapping of Strings matching a valid ObjectId for unresolvable paths.

We now make sure we to not convert Strings representing valid ObjectIds into the such for paths that cannot be resolved to a Property.

Original pull request: #732.
This commit is contained in:
Christoph Strobl
2019-03-26 08:11:15 +01:00
committed by Mark Paluch
parent 9a64830e95
commit d7cd97ea89
2 changed files with 61 additions and 13 deletions

View File

@@ -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,17 +1039,16 @@ public class QueryMapper {
@Nullable
private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpression) {
String rawPath = pathExpression.replaceAll("\\.\\d+", "") //
.replaceAll(POSITIONAL_OPERATOR.pattern(), "");
PropertyPath path = forName(rawPath);
if (path == null || isPathToJavaLangClassProperty(path)) {
return null;
}
try {
String rawPath = pathExpression.replaceAll("\\.\\d+", "") //
.replaceAll(POSITIONAL_OPERATOR.pattern(), "");
PropertyPath path = PropertyPath.from(rawPath, entity.getTypeInformation());
if (isPathToJavaLangClassProperty(path)) {
return null;
}
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
@@ -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;
}
}

View File

@@ -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 {