Skip to content

Commit 99eb849

Browse files
christophstroblmp911de
authored andcommitted
Fix query mapper path resolution for types considered simple ones.
spring-projects/spring-data-commons#2293 changed how PersistentProperty paths get resolved and considers potentially registered converters for those, which made the path resolution fail in during the query mapping process. This commit makes sure to capture the according exception and continue with the given user input. Fixes: #3659 Original pull request: #3661.
1 parent d33aa68 commit 99eb849

File tree

2 files changed

+87
-17
lines changed

2 files changed

+87
-17
lines changed

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

+39-17
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919
import java.util.Map.Entry;
2020
import java.util.regex.Matcher;
2121
import java.util.regex.Pattern;
22+
import java.util.stream.Collectors;
2223

2324
import org.bson.BsonValue;
2425
import org.bson.Document;
2526
import org.bson.conversions.Bson;
2627
import org.bson.types.ObjectId;
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
2730
import org.springframework.core.convert.ConversionService;
2831
import org.springframework.core.convert.converter.Converter;
2932
import org.springframework.data.domain.Example;
@@ -68,6 +71,8 @@
6871
*/
6972
public class QueryMapper {
7073

74+
protected static final Logger LOGGER = LoggerFactory.getLogger(QueryMapper.class);
75+
7176
private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
7277
private static final Document META_TEXT_SCORE = new Document("$meta", "textScore");
7378
static final ClassTypeInformation<?> NESTED_DOCUMENT = ClassTypeInformation.from(NestedDocument.class);
@@ -1173,38 +1178,55 @@ private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpre
11731178
removePlaceholders(DOT_POSITIONAL_PATTERN, pathExpression));
11741179

11751180
if (sourceProperty != null && sourceProperty.getOwner().equals(entity)) {
1176-
return mappingContext
1177-
.getPersistentPropertyPath(PropertyPath.from(Pattern.quote(sourceProperty.getName()), entity.getTypeInformation()));
1181+
return mappingContext.getPersistentPropertyPath(
1182+
PropertyPath.from(Pattern.quote(sourceProperty.getName()), entity.getTypeInformation()));
11781183
}
11791184

11801185
PropertyPath path = forName(rawPath);
11811186
if (path == null || isPathToJavaLangClassProperty(path)) {
11821187
return null;
11831188
}
11841189

1185-
try {
1190+
PersistentPropertyPath<MongoPersistentProperty> propertyPath = tryToResolvePersistentPropertyPath(path);
11861191

1187-
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
1192+
if (propertyPath == null) {
11881193

1189-
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
1190-
boolean associationDetected = false;
1194+
if (QueryMapper.LOGGER.isInfoEnabled()) {
1195+
1196+
String types = StringUtils.collectionToDelimitedString(
1197+
path.stream().map(it -> it.getType().getSimpleName()).collect(Collectors.toList()), " -> ");
1198+
QueryMapper.LOGGER.info(
1199+
"Could not map '{}'. Maybe a fragment in '{}' is considered a simple type. Mapper continues with {}.",
1200+
path, types, pathExpression);
1201+
}
1202+
return null;
1203+
}
11911204

1192-
while (iterator.hasNext()) {
1205+
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
1206+
boolean associationDetected = false;
11931207

1194-
MongoPersistentProperty property = iterator.next();
1208+
while (iterator.hasNext()) {
11951209

1196-
if (property.isAssociation()) {
1197-
associationDetected = true;
1198-
continue;
1199-
}
1210+
MongoPersistentProperty property = iterator.next();
12001211

1201-
if (associationDetected && !property.isIdProperty()) {
1202-
throw new MappingException(String.format(INVALID_ASSOCIATION_REFERENCE, pathExpression));
1203-
}
1212+
if (property.isAssociation()) {
1213+
associationDetected = true;
1214+
continue;
12041215
}
12051216

1206-
return propertyPath;
1207-
} catch (InvalidPersistentPropertyPath e) {
1217+
if (associationDetected && !property.isIdProperty()) {
1218+
throw new MappingException(String.format(INVALID_ASSOCIATION_REFERENCE, pathExpression));
1219+
}
1220+
}
1221+
1222+
return propertyPath;
1223+
}
1224+
1225+
private PersistentPropertyPath<MongoPersistentProperty> tryToResolvePersistentPropertyPath(PropertyPath path) {
1226+
1227+
try {
1228+
return mappingContext.getPersistentPropertyPath(path);
1229+
} catch (MappingException e) {
12081230
return null;
12091231
}
12101232
}

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

+48
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.Map;
2929
import java.util.Optional;
3030

31+
import lombok.Data;
3132
import org.bson.conversions.Bson;
3233
import org.bson.types.Code;
3334
import org.bson.types.ObjectId;
@@ -36,8 +37,10 @@
3637
import org.junit.jupiter.api.extension.ExtendWith;
3738
import org.mockito.Mock;
3839
import org.mockito.junit.jupiter.MockitoExtension;
40+
import org.springframework.core.convert.converter.Converter;
3941
import org.springframework.data.annotation.Id;
4042
import org.springframework.data.annotation.Transient;
43+
import org.springframework.data.convert.WritingConverter;
4144
import org.springframework.data.domain.Sort;
4245
import org.springframework.data.domain.Sort.Direction;
4346
import org.springframework.data.geo.Point;
@@ -52,6 +55,7 @@
5255
import org.springframework.data.mongodb.core.mapping.FieldType;
5356
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
5457
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
58+
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
5559
import org.springframework.data.mongodb.core.mapping.TextScore;
5660
import org.springframework.data.mongodb.core.mapping.Unwrapped;
5761
import org.springframework.data.mongodb.core.query.BasicQuery;
@@ -1276,6 +1280,26 @@ void mapsNullValueForFieldWithCustomTargetType() {
12761280
.isThrownBy(() -> mapper.getMappedObject(query.getQueryObject(), context.getPersistentEntity(Foo.class)));
12771281
}
12781282

1283+
@Test // GH-3659
1284+
void allowsUsingFieldPathsForPropertiesHavingCustomConversionRegistered() {
1285+
1286+
Query query = query(where("address.street").is("1007 Mountain Drive"));
1287+
1288+
MongoCustomConversions mongoCustomConversions = new MongoCustomConversions(Collections.singletonList(new MyAddressToDocumentConverter()));
1289+
1290+
this.context = new MongoMappingContext();
1291+
this.context.setSimpleTypeHolder(mongoCustomConversions.getSimpleTypeHolder());
1292+
this.context.afterPropertiesSet();
1293+
1294+
this.converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context);
1295+
this.converter.setCustomConversions(mongoCustomConversions);
1296+
this.converter.afterPropertiesSet();
1297+
1298+
this.mapper = new QueryMapper(converter);
1299+
1300+
assertThat(mapper.getMappedSort(query.getQueryObject(), context.getPersistentEntity(Customer.class))).isEqualTo(new org.bson.Document("address.street", "1007 Mountain Drive"));
1301+
}
1302+
12791303
class WithDeepArrayNesting {
12801304

12811305
List<WithNestedArray> level0;
@@ -1506,4 +1530,28 @@ static class WithPropertyUsingUnderscoreInName {
15061530
@Field("renamed")
15071531
String renamed_fieldname_with_underscores;
15081532
}
1533+
1534+
@Document
1535+
static class Customer {
1536+
1537+
@Id
1538+
private ObjectId id;
1539+
private String name;
1540+
private MyAddress address;
1541+
}
1542+
1543+
static class MyAddress {
1544+
private String street;
1545+
}
1546+
1547+
@WritingConverter
1548+
public static class MyAddressToDocumentConverter implements Converter<MyAddress, org.bson.Document> {
1549+
1550+
@Override
1551+
public org.bson.Document convert(MyAddress address) {
1552+
org.bson.Document doc = new org.bson.Document();
1553+
doc.put("street", address.street);
1554+
return doc;
1555+
}
1556+
}
15091557
}

0 commit comments

Comments
 (0)