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.
This commit is contained in:
Oliver Gierke
2017-03-06 16:19:11 +01:00
parent f42c24a605
commit 93f81f7321
2 changed files with 37 additions and 7 deletions

View File

@@ -1001,16 +1001,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
doInsert(collectionName, objectToSave, this.mongoConverter);
} else {
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
assertUpdateableIdIfNotSet(objectToSave);
// Create query for entity with the id and old version
Object id = convertingAccessor.getProperty(idProperty);
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
// Bump version number
convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1);
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
assertUpdateableIdIfNotSet(objectToSave);
BasicDBObject dbObject = new BasicDBObject();
this.mongoConverter.write(objectToSave, dbObject);
@@ -1018,6 +1014,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbObject, collectionName));
Update update = Update.fromDBObject(dbObject, ID_FIELD);
// Create query for entity with the id and old version
Object id = convertingAccessor.getProperty(idProperty);
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
doUpdate(collectionName, query, update, objectToSave.getClass(), false, false);
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbObject, collectionName));
}

View File

@@ -52,6 +52,8 @@ import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
@@ -72,6 +74,7 @@ import com.mongodb.MapReduceOutput;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
import com.mongodb.WriteResult;
/**
* Unit tests for {@link MongoTemplate}.
@@ -465,6 +468,33 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
assertThat(captor.getValue().getLimit(), is(1000));
}
@Test // DATAMONGO-1639
public void beforeConvertEventForUpdateSeesNextVersion() {
final VersionedEntity entity = new VersionedEntity();
entity.id = 1;
entity.version = 0;
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
context.addApplicationListener(new AbstractMongoEventListener<VersionedEntity>() {
@Override
public void onBeforeConvert(BeforeConvertEvent<VersionedEntity> event) {
assertThat(event.getSource().version, is(1));
}
});
template.setApplicationContext(context);
MongoTemplate spy = Mockito.spy(template);
doReturn(mock(WriteResult.class)).when(spy).doUpdate(anyString(), Mockito.any(Query.class),
Mockito.any(Update.class), Mockito.any(Class.class), anyBoolean(), anyBoolean());
spy.save(entity);
}
class AutogenerateableId {
@Id BigInteger id;