Skip to content

Commit 27af3c7

Browse files
committed
GH-5166 - Apply BeforeConvertCallback result in MongoTemplate.replace()
1 parent e335192 commit 27af3c7

4 files changed

Lines changed: 96 additions & 14 deletions

File tree

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
* @author Michael Krog
187187
* @author Jakub Zurawa
188188
* @author Florian Lüdiger
189+
* @author Sujay HK
189190
*/
190191
public class MongoTemplate implements MongoOperations, ApplicationContextAware, IndexOperationsProvider,
191192
SearchIndexOperationsProvider, ReadPreferenceAware {
@@ -2184,7 +2185,7 @@ public <T> UpdateResult replace(Query query, T replacement, ReplaceOptions optio
21842185
}
21852186

21862187
protected <S, T> UpdateResult replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options,
2187-
String collectionName) {
2188+
String collectionName) {
21882189

21892190
Assert.notNull(query, "Query must not be null");
21902191
Assert.notNull(replacement, "Replacement must not be null");
@@ -2195,10 +2196,10 @@ protected <S, T> UpdateResult replace(Query query, Class<S> entityType, T replac
21952196
Assert.isTrue(query.getLimit() <= 1, "Query must not define a limit other than 1 ore none");
21962197
Assert.isTrue(query.getSkip() <= 0, "Query must not define skip");
21972198

2199+
replacement = maybeCallBeforeConvert(replacement, collectionName);
21982200
UpdateContext updateContext = queryOperations.replaceSingleContext(query,
21992201
operations.forEntity(replacement).toMappedDocument(this.mongoConverter), options.isUpsert());
22002202

2201-
replacement = maybeCallBeforeConvert(replacement, collectionName);
22022203
Document mappedReplacement = updateContext.getMappedUpdate(mappingContext.getPersistentEntity(entityType));
22032204
maybeEmitEvent(new BeforeSaveEvent<>(replacement, mappedReplacement, collectionName));
22042205
replacement = maybeCallBeforeSave(replacement, mappedReplacement, collectionName);

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
* @author Yadhukrishna S Pai
195195
* @author Florian Lüdiger
196196
* @author Kyuhong Han
197+
* @author Sujay HK
197198
* @since 2.0
198199
*/
199200
public class ReactiveMongoTemplate implements ReactiveMongoOperations, ApplicationContextAware {
@@ -2095,25 +2096,29 @@ public <T> Mono<UpdateResult> replace(Query query, T replacement, ReplaceOptions
20952096
}
20962097

20972098
protected <S, T> Mono<UpdateResult> replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options,
2098-
String collectionName) {
2099+
String collectionName) {
20992100

21002101
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
2101-
UpdateContext updateContext = queryOperations.replaceSingleContext(query,
2102-
operations.forEntity(replacement).toMappedDocument(this.mongoConverter), options.isUpsert());
21032102

2104-
return createMono(collectionName, collection -> {
2103+
return maybeCallBeforeConvert(replacement, collectionName).flatMap(converted -> {
2104+
2105+
UpdateContext updateContext = queryOperations.replaceSingleContext(query,
2106+
operations.forEntity(converted).toMappedDocument(this.mongoConverter), options.isUpsert());
21052107

2106-
Document mappedUpdate = updateContext.getMappedUpdate(entity);
2108+
return createMono(collectionName, collection -> {
21072109

2108-
MongoAction action = new MongoAction(writeConcern, MongoActionOperation.REPLACE, collectionName, entityType,
2109-
mappedUpdate, updateContext.getQueryObject());
2110+
Document mappedUpdate = updateContext.getMappedUpdate(entity);
21102111

2111-
MongoCollection<Document> collectionToUse = createCollectionPreparer(query, action).prepare(collection);
2112+
MongoAction action = new MongoAction(writeConcern, MongoActionOperation.REPLACE, collectionName, entityType,
2113+
mappedUpdate, updateContext.getQueryObject());
21122114

2113-
return collectionToUse.replaceOne(updateContext.getMappedQuery(entity), mappedUpdate,
2114-
updateContext.getReplaceOptions(entity, it -> {
2115-
it.upsert(options.isUpsert());
2116-
}));
2115+
MongoCollection<Document> collectionToUse = createCollectionPreparer(query, action).prepare(collection);
2116+
2117+
return collectionToUse.replaceOne(updateContext.getMappedQuery(entity), mappedUpdate,
2118+
updateContext.getReplaceOptions(entity, it -> {
2119+
it.upsert(options.isUpsert());
2120+
}));
2121+
});
21172122
});
21182123
}
21192124

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import org.springframework.data.domain.Sort;
7474
import org.springframework.data.domain.Sort.Direction;
7575
import org.springframework.data.mapping.MappingException;
76+
import org.springframework.data.mapping.callback.EntityCallbacks;
7677
import org.springframework.data.mapping.context.PersistentEntities;
7778
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
7879
import org.springframework.data.mongodb.MongoDatabaseFactory;
@@ -95,8 +96,10 @@
9596
import org.springframework.data.mongodb.core.mapping.Field;
9697
import org.springframework.data.mongodb.core.mapping.FieldName.Type;
9798
import org.springframework.data.mongodb.core.mapping.MongoId;
99+
import org.springframework.data.mongodb.core.mapping.Document;
98100
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
99101
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
102+
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
100103
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
101104
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
102105
import org.springframework.data.mongodb.core.query.BasicQuery;
@@ -144,6 +147,7 @@
144147
* @author duozhilin
145148
* @author Jakub Zurawa
146149
* @author Florian Lüdiger
150+
* @author Sujay HK
147151
*/
148152
public class MongoTemplateTests {
149153

@@ -4099,6 +4103,29 @@ void readsMapWithDotInKey() {
40994103
assertThat(loaded.mapValue).isEqualTo(sourceMap);
41004104
}
41014105

4106+
@Test // GH-5166
4107+
void beforeConvertCallbackIsAppliedOnReplace() {
4108+
4109+
PersonWithConvertedName person = new PersonWithConvertedName("sujay");
4110+
template.insert(person);
4111+
4112+
// Register a BeforeConvertCallback that uppercases the name
4113+
template.setEntityCallbacks(EntityCallbacks.create(
4114+
(BeforeConvertCallback<PersonWithConvertedName>) (entity, collection) -> {
4115+
entity.name = entity.name.toUpperCase();
4116+
return entity;
4117+
}
4118+
));
4119+
4120+
PersonWithConvertedName replacement = new PersonWithConvertedName("sujay");
4121+
replacement.id = person.id;
4122+
4123+
template.replace(query(where("id").is(person.id)), replacement);
4124+
4125+
PersonWithConvertedName found = template.findById(person.id, PersonWithConvertedName.class);
4126+
assertThat(found.name).isEqualTo("SUJAY"); // will FAIL before the fix
4127+
}
4128+
41024129
private AtomicReference<ImmutableVersioned> createAfterSaveReference() {
41034130

41044131
AtomicReference<ImmutableVersioned> saved = new AtomicReference<>();
@@ -4113,6 +4140,17 @@ public void onAfterSave(AfterSaveEvent<ImmutableVersioned> event) {
41134140
return saved;
41144141
}
41154142

4143+
@org.springframework.data.mongodb.core.mapping.Document
4144+
static class PersonWithConvertedName {
4145+
4146+
@Id String id;
4147+
String name;
4148+
4149+
PersonWithConvertedName(String name) {
4150+
this.name = name;
4151+
}
4152+
}
4153+
41164154
static class TypeWithNumbers {
41174155

41184156
@Id String id;
@@ -4813,6 +4851,7 @@ public void onBeforeConvert(BeforeConvertEvent<PersonWithIdPropertyOfTypeUUID> e
48134851

48144852
person.setId(UUID.randomUUID());
48154853
}
4854+
48164855
}
48174856

48184857
public static class Message {
@@ -5097,4 +5136,5 @@ public int hashCode() {
50975136
return Objects.hash(id, value, mapValue);
50985137
}
50995138
}
5139+
51005140
}

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
7272
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
7373
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
74+
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeConvertCallback;
75+
import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
7476
import org.springframework.data.mongodb.core.query.Criteria;
7577
import org.springframework.data.mongodb.core.query.NearQuery;
7678
import org.springframework.data.mongodb.core.query.Query;
@@ -89,6 +91,7 @@
8991
*
9092
* @author Mark Paluch
9193
* @author Christoph Strobl
94+
* @author Sujay HK
9295
*/
9396
public class ReactiveMongoTemplateTests {
9497

@@ -2101,6 +2104,28 @@ public void doesNotFailOnInsertForEntityWithNonAutogeneratableId3() {
21012104
template.save(source).as(StepVerifier::create).expectNextCount(1).verifyComplete();
21022105
}
21032106

2107+
@Test // GH-5166
2108+
void beforeConvertCallbackIsAppliedOnReplace() {
2109+
2110+
PersonWithConvertedName person = new PersonWithConvertedName("sujay");
2111+
template.insert(person).block();
2112+
2113+
template.setEntityCallbacks(ReactiveEntityCallbacks.create(
2114+
(ReactiveBeforeConvertCallback<PersonWithConvertedName>) (entity, collection) -> {
2115+
entity.name = entity.name.toUpperCase();
2116+
return Mono.just(entity);
2117+
}
2118+
));
2119+
2120+
PersonWithConvertedName replacement = new PersonWithConvertedName("sujay");
2121+
replacement.id = person.id;
2122+
2123+
template.replace(query(where("id").is(person.id)), replacement).block();
2124+
2125+
PersonWithConvertedName found = template.findById(person.id, PersonWithConvertedName.class).block();
2126+
assertThat(found.name).isEqualTo("SUJAY");
2127+
}
2128+
21042129
static class NonAutogeneratableId {
21052130

21062131
@Id IdObject id;
@@ -2136,6 +2161,17 @@ public void setVersion(int version) {
21362161
}
21372162
}
21382163

2164+
@org.springframework.data.mongodb.core.mapping.Document
2165+
static class PersonWithConvertedName {
2166+
2167+
@Id String id;
2168+
String name;
2169+
2170+
PersonWithConvertedName(String name) {
2171+
this.name = name;
2172+
}
2173+
}
2174+
21392175
record IdObject(String value, long timestamp) {
21402176

21412177
}

0 commit comments

Comments
 (0)