Skip to content

Commit 98d655f

Browse files
committed
DATAMONGO-1639 - Make sure BeforeConvertEvent sees new version for updates.
The changes for DATAMONGO-1617 subtley changed the behavior for entity updates in terms of the version value they see for entities using optimistic locking. Previously the updates already saw the new version value, where after the fix for DATAMONGO-1617 it saw the old one. That caused BeforeConvertEvent listeners not being able to distinguish between an original insert and the first update anymore. This change is now rolled back and we introduced a test case that encodes this expectation explicitly.
1 parent 98a9b66 commit 98d655f

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -997,23 +997,23 @@ private <T> void doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity
997997
doInsert(collectionName, objectToSave, this.mongoConverter);
998998
} else {
999999

1000-
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
1001-
assertUpdateableIdIfNotSet(objectToSave);
1002-
1003-
// Create query for entity with the id and old version
1004-
Object id = convertingAccessor.getProperty(idProperty);
1005-
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
1006-
10071000
// Bump version number
10081001
convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1);
10091002

1003+
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
1004+
assertUpdateableIdIfNotSet(objectToSave);
1005+
10101006
Document document = new Document();
10111007

10121008
this.mongoConverter.write(objectToSave, document);
10131009

10141010
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, document, collectionName));
10151011
Update update = Update.fromDocument(document, ID_FIELD);
10161012

1013+
// Create query for entity with the id and old version
1014+
Object id = convertingAccessor.getProperty(idProperty);
1015+
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
1016+
10171017
UpdateResult result = doUpdate(collectionName, query, update, objectToSave.getClass(), false, false);
10181018

10191019
if (result.getModifiedCount() == 0) {

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

+33
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
import org.springframework.data.mongodb.core.convert.QueryMapper;
5757
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
5858
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
59+
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
60+
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
5961
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
6062
import org.springframework.data.mongodb.core.query.BasicQuery;
6163
import org.springframework.data.mongodb.core.query.Criteria;
@@ -75,6 +77,7 @@
7577
import com.mongodb.client.MongoDatabase;
7678
import com.mongodb.client.model.FindOneAndUpdateOptions;
7779
import com.mongodb.client.model.UpdateOptions;
80+
import com.mongodb.client.result.UpdateResult;
7881

7982
/**
8083
* Unit tests for {@link MongoTemplate}.
@@ -498,6 +501,36 @@ public void mapReduceShouldPickUpLimitFromOptionsEvenWhenQueryDefinesItDifferent
498501
verify(output, times(1)).limit(1000);
499502
}
500503

504+
@Test // DATAMONGO-1639
505+
public void beforeConvertEventForUpdateSeesNextVersion() {
506+
507+
final VersionedEntity entity = new VersionedEntity();
508+
entity.id = 1;
509+
entity.version = 0;
510+
511+
GenericApplicationContext context = new GenericApplicationContext();
512+
context.refresh();
513+
context.addApplicationListener(new AbstractMongoEventListener<VersionedEntity>() {
514+
515+
@Override
516+
public void onBeforeConvert(BeforeConvertEvent<VersionedEntity> event) {
517+
assertThat(event.getSource().version, is(1));
518+
}
519+
});
520+
521+
template.setApplicationContext(context);
522+
523+
MongoTemplate spy = Mockito.spy(template);
524+
525+
UpdateResult result = mock(UpdateResult.class);
526+
doReturn(1L).when(result).getModifiedCount();
527+
528+
doReturn(result).when(spy).doUpdate(anyString(), Mockito.any(Query.class), Mockito.any(Update.class),
529+
Mockito.any(Class.class), anyBoolean(), anyBoolean());
530+
531+
spy.save(entity);
532+
}
533+
501534
class AutogenerateableId {
502535

503536
@Id BigInteger id;

0 commit comments

Comments
 (0)