Skip to content

Commit 4673e3d

Browse files
christophstroblThomas Darimont
authored andcommitted
DATAMONGO-1077 - Fix Update removing $ operator for DBRef.
We now retain the positional parameter "$" when mapping field names for associations. Orignal pull request: spring-projects#235.
1 parent 00e48cc commit 4673e3d

File tree

3 files changed

+105
-8
lines changed

3 files changed

+105
-8
lines changed

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,7 @@ private final Association<MongoPersistentProperty> findAssociation() {
792792
*/
793793
@Override
794794
public String getMappedKey() {
795-
return path == null ? name : path.toDotPath(isAssociation() ? new AssociationConverter(getAssociation())
796-
: getPropertyConverter());
795+
return path == null ? name : path.toDotPath(isAssociation() ? getAssociationConverter() : getPropertyConverter());
797796
}
798797

799798
protected PersistentPropertyPath<MongoPersistentProperty> getPath() {
@@ -845,6 +844,17 @@ private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpre
845844
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
846845
return PropertyToFieldNameConverter.INSTANCE;
847846
}
847+
848+
/**
849+
* Return the {@link Converter} to use for creating the mapped key of an association. Default implementation is
850+
* {@link AssociationConverter}.
851+
*
852+
* @return
853+
* @since 1.7
854+
*/
855+
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
856+
return new AssociationConverter(getAssociation());
857+
}
848858
}
849859

850860
/**

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Map.Entry;
2121

2222
import org.springframework.core.convert.converter.Converter;
23+
import org.springframework.data.mapping.Association;
2324
import org.springframework.data.mapping.context.MappingContext;
2425
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
2526
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
@@ -193,18 +194,60 @@ public String getMappedKey() {
193194
*/
194195
@Override
195196
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
196-
return isAssociation() ? new AssociationConverter(getAssociation()) : new UpdatePropertyConverter(key);
197+
return new UpdatePropertyConverter(key);
198+
}
199+
200+
/*
201+
* (non-Javadoc)
202+
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getAssociationConverter()
203+
*/
204+
@Override
205+
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
206+
return new UpdateAssociationConverter(getAssociation(), key);
207+
}
208+
209+
/**
210+
* Special mapper handling positional parameter {@literal $} within property names.
211+
*
212+
* @author Christoph Strobl
213+
* @since 1.7
214+
*/
215+
private static class UpdateKeyMapper {
216+
217+
private final Iterator<String> iterator;
218+
219+
protected UpdateKeyMapper(String rawKey) {
220+
221+
Assert.hasText(rawKey, "Key must not be null or empty!");
222+
223+
this.iterator = Arrays.asList(rawKey.split("\\.")).iterator();
224+
this.iterator.next();
225+
}
226+
227+
/**
228+
* Maps the property name while retaining potential positional operator {@literal $}.
229+
*
230+
* @param property
231+
* @return
232+
*/
233+
protected String mapPropertyName(MongoPersistentProperty property) {
234+
235+
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
236+
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
237+
}
238+
197239
}
198240

199241
/**
200242
* Special {@link Converter} for {@link MongoPersistentProperty} instances that will concatenate the {@literal $}
201243
* contained in the source update key.
202244
*
203245
* @author Oliver Gierke
246+
* @author Christoph Strobl
204247
*/
205248
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
206249

207-
private final Iterator<String> iterator;
250+
private final UpdateKeyMapper mapper;
208251

209252
/**
210253
* Creates a new {@link UpdatePropertyConverter} with the given update key.
@@ -215,8 +258,7 @@ public UpdatePropertyConverter(String updateKey) {
215258

216259
Assert.hasText(updateKey, "Update key must not be null or empty!");
217260

218-
this.iterator = Arrays.asList(updateKey.split("\\.")).iterator();
219-
this.iterator.next();
261+
this.mapper = new UpdateKeyMapper(updateKey);
220262
}
221263

222264
/*
@@ -225,9 +267,37 @@ public UpdatePropertyConverter(String updateKey) {
225267
*/
226268
@Override
227269
public String convert(MongoPersistentProperty property) {
270+
return mapper.mapPropertyName(property);
271+
}
272+
}
228273

229-
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
230-
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
274+
/**
275+
* {@link Converter} retaining positional parameter {@literal $} for {@link Association}s.
276+
*
277+
* @author Christoph Strobl
278+
*/
279+
protected static class UpdateAssociationConverter extends AssociationConverter {
280+
281+
private final UpdateKeyMapper mapper;
282+
283+
/**
284+
* Creates a new {@link AssociationConverter} for the given {@link Association}.
285+
*
286+
* @param association must not be {@literal null}.
287+
*/
288+
public UpdateAssociationConverter(Association<MongoPersistentProperty> association, String key) {
289+
290+
super(association);
291+
this.mapper = new UpdateKeyMapper(key);
292+
}
293+
294+
/*
295+
* (non-Javadoc)
296+
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
297+
*/
298+
@Override
299+
public String convert(MongoPersistentProperty source) {
300+
return super.convert(source) == null ? null : mapper.mapPropertyName(source);
231301
}
232302
}
233303
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,23 @@ public void updateMapperConvertsPullWithNestedQuerfyOnDBRefCorrectly() {
508508
assertThat(list, equalTo(new BasicDBObjectBuilder().add("_id", "1").get()));
509509
}
510510

511+
/**
512+
* @see DATAMONGO-1077
513+
*/
514+
@Test
515+
public void shouldNotRemovePositionalParameter() {
516+
517+
Update update = new Update();
518+
update.unset("dbRefAnnotatedList.$");
519+
520+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
521+
context.getPersistentEntity(DocumentWithDBRefCollection.class));
522+
523+
DBObject $unset = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$unset");
524+
525+
assertThat($unset, equalTo(new BasicDBObjectBuilder().add("dbRefAnnotatedList.$", 1).get()));
526+
}
527+
511528
@org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface")
512529
static interface DocumentWithReferenceToInterface {
513530

0 commit comments

Comments
 (0)