Browse Source

DATAMONGO-1992 - Add mutation support for immutable objects through MongoTemplate and SimpleMongoRepository.

Persisting methods of MongoTemplate and SimpleMongoRepository now return potentially new object instances of immutable objects. New instances are created using wither methods/Kotlin copy(…) methods if an immutable object requires association with an Id or the version number needs to be incremented.
pull/587/merge
Mark Paluch 8 years ago committed by Oliver Gierke
parent
commit
d1dea13c32
  1. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableInsertOperation.java
  2. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableInsertOperationSupport.java
  3. 21
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
  4. 142
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  5. 19
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java
  6. 29
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java

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

@ -63,17 +63,19 @@ public interface ExecutableInsertOperation {
* Insert exactly one object. * Insert exactly one object.
* *
* @param object must not be {@literal null}. * @param object must not be {@literal null}.
* @return the inserted object.
* @throws IllegalArgumentException if object is {@literal null}. * @throws IllegalArgumentException if object is {@literal null}.
*/ */
void one(T object); T one(T object);
/** /**
* Insert a collection of objects. * Insert a collection of objects.
* *
* @param objects must not be {@literal null}. * @param objects must not be {@literal null}.
* @return the inserted objects.
* @throws IllegalArgumentException if objects is {@literal null}. * @throws IllegalArgumentException if objects is {@literal null}.
*/ */
void all(Collection<? extends T> objects); Collection<? extends T> all(Collection<? extends T> objects);
} }
/** /**

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

@ -72,11 +72,11 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingInsert#insert(java.lang.Class) * @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingInsert#insert(java.lang.Class)
*/ */
@Override @Override
public void one(T object) { public T one(T object) {
Assert.notNull(object, "Object must not be null!"); Assert.notNull(object, "Object must not be null!");
template.insert(object, getCollectionName()); return template.insert(object, getCollectionName());
} }
/* /*
@ -84,11 +84,11 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
* @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingInsert#all(java.util.Collection) * @see org.springframework.data.mongodb.core.ExecutableInsertOperation.TerminatingInsert#all(java.util.Collection)
*/ */
@Override @Override
public void all(Collection<? extends T> objects) { public Collection<T> all(Collection<? extends T> objects) {
Assert.notNull(objects, "Objects must not be null!"); Assert.notNull(objects, "Objects must not be null!");
template.insert(objects, getCollectionName()); return template.insert(objects, getCollectionName());
} }
/* /*

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

@ -1141,8 +1141,9 @@ public interface MongoOperations extends FluentMongoOperations {
* Insert is used to initially store the object into the database. To update an existing object use the save method. * Insert is used to initially store the object into the database. To update an existing object use the save method.
* *
* @param objectToSave the object to store in the collection. Must not be {@literal null}. * @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the inserted object.
*/ */
void insert(Object objectToSave); <T> T insert(T objectToSave);
/** /**
* Insert the object into the specified collection. * Insert the object into the specified collection.
@ -1154,32 +1155,36 @@ public interface MongoOperations extends FluentMongoOperations {
* *
* @param objectToSave the object to store in the collection. Must not be {@literal null}. * @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @param collectionName name of the collection to store the object in. Must not be {@literal null}. * @param collectionName name of the collection to store the object in. Must not be {@literal null}.
* @return the inserted object.
*/ */
void insert(Object objectToSave, String collectionName); <T> T insert(T objectToSave, String collectionName);
/** /**
* Insert a Collection of objects into a collection in a single batch write to the database. * Insert a Collection of objects into a collection in a single batch write to the database.
* *
* @param batchToSave the batch of objects to save. Must not be {@literal null}. * @param batchToSave the batch of objects to save. Must not be {@literal null}.
* @param entityClass class that determines the collection to use. Must not be {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}.
* @return the inserted objects that.
*/ */
void insert(Collection<? extends Object> batchToSave, Class<?> entityClass); <T> Collection<T> insert(Collection<? extends T> batchToSave, Class<?> entityClass);
/** /**
* Insert a batch of objects into the specified collection in a single batch write to the database. * Insert a batch of objects into the specified collection in a single batch write to the database.
* *
* @param batchToSave the list of objects to save. Must not be {@literal null}. * @param batchToSave the list of objects to save. Must not be {@literal null}.
* @param collectionName name of the collection to store the object in. Must not be {@literal null}. * @param collectionName name of the collection to store the object in. Must not be {@literal null}.
* @return the inserted objects that.
*/ */
void insert(Collection<? extends Object> batchToSave, String collectionName); <T> Collection<T> insert(Collection<? extends T> batchToSave, String collectionName);
/** /**
* Insert a mixed Collection of objects into a database collection determining the collection name to use based on the * Insert a mixed Collection of objects into a database collection determining the collection name to use based on the
* class. * class.
* *
* @param objectsToSave the list of objects to save. Must not be {@literal null}. * @param objectsToSave the list of objects to save. Must not be {@literal null}.
* @return the inserted objects.
*/ */
void insertAll(Collection<? extends Object> objectsToSave); <T> Collection<T> insertAll(Collection<? extends T> objectsToSave);
/** /**
* Save the object to the collection for the entity type of the object to save. This will perform an insert if the * Save the object to the collection for the entity type of the object to save. This will perform an insert if the
@ -1195,8 +1200,9 @@ public interface MongoOperations extends FluentMongoOperations {
* Conversion"</a> for more details. * Conversion"</a> for more details.
* *
* @param objectToSave the object to store in the collection. Must not be {@literal null}. * @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @return the saved object.
*/ */
void save(Object objectToSave); <T> T save(T objectToSave);
/** /**
* Save the object to the specified collection. This will perform an insert if the object is not already present, that * Save the object to the specified collection. This will perform an insert if the object is not already present, that
@ -1213,8 +1219,9 @@ public interface MongoOperations extends FluentMongoOperations {
* *
* @param objectToSave the object to store in the collection. Must not be {@literal null}. * @param objectToSave the object to store in the collection. Must not be {@literal null}.
* @param collectionName name of the collection to store the object in. Must not be {@literal null}. * @param collectionName name of the collection to store the object in. Must not be {@literal null}.
* @return the saved object.
*/ */
void save(Object objectToSave, String collectionName); <T> T save(T objectToSave, String collectionName);
/** /**
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by * Performs an upsert. If no document is found that matches the query, a new document is created and inserted by

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

@ -73,16 +73,7 @@ import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.Fields; import org.springframework.data.mongodb.core.aggregation.Fields;
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext; import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation; import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.DbRefResolver; import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.JsonSchemaMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MongoJsonSchemaMapper;
import org.springframework.data.mongodb.core.convert.MongoWriter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
import org.springframework.data.mongodb.core.index.IndexOperations; import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.index.IndexOperationsProvider; import org.springframework.data.mongodb.core.index.IndexOperationsProvider;
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher; import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
@ -1157,12 +1148,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object) * @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object)
*/ */
@Override @Override
public void insert(Object objectToSave) { public <T> T insert(T objectToSave) {
Assert.notNull(objectToSave, "ObjectToSave must not be null!"); Assert.notNull(objectToSave, "ObjectToSave must not be null!");
ensureNotIterable(objectToSave); ensureNotIterable(objectToSave);
insert(objectToSave, determineEntityCollectionName(objectToSave)); return insert(objectToSave, determineEntityCollectionName(objectToSave));
} }
/* /*
@ -1170,13 +1161,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object, java.lang.String) * @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object, java.lang.String)
*/ */
@Override @Override
public void insert(Object objectToSave, String collectionName) { public <T> T insert(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "ObjectToSave must not be null!"); Assert.notNull(objectToSave, "ObjectToSave must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!"); Assert.notNull(collectionName, "CollectionName must not be null!");
ensureNotIterable(objectToSave); ensureNotIterable(objectToSave);
doInsert(collectionName, objectToSave, this.mongoConverter); return (T) doInsert(collectionName, objectToSave, this.mongoConverter);
} }
protected void ensureNotIterable(@Nullable Object o) { protected void ensureNotIterable(@Nullable Object o) {
@ -1230,19 +1221,21 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return wc; return wc;
} }
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) { protected <T> T doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
initializeVersionProperty(objectToSave); T toSave = (T) initializeVersionProperty(objectToSave);
maybeEmitEvent(new BeforeConvertEvent<>(objectToSave, collectionName)); maybeEmitEvent(new BeforeConvertEvent<>(toSave, collectionName));
assertUpdateableIdIfNotSet(objectToSave); assertUpdateableIdIfNotSet(toSave);
Document dbDoc = toDocument(objectToSave, writer); Document dbDoc = toDocument(toSave, writer);
maybeEmitEvent(new BeforeSaveEvent<>(objectToSave, dbDoc, collectionName)); maybeEmitEvent(new BeforeSaveEvent<>(toSave, dbDoc, collectionName));
Object id = insertDocument(collectionName, dbDoc, objectToSave.getClass()); Object id = insertDocument(collectionName, dbDoc, toSave.getClass());
T saved = (T) populateIdIfNecessary(toSave, id);
maybeEmitEvent(new AfterSaveEvent<>(saved, dbDoc, collectionName));
populateIdIfNecessary(objectToSave, id); return saved;
maybeEmitEvent(new AfterSaveEvent<>(objectToSave, dbDoc, collectionName));
} }
/** /**
@ -1275,7 +1268,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
} }
} }
private void initializeVersionProperty(Object entity) { private Object initializeVersionProperty(Object entity) {
MongoPersistentEntity<?> persistentEntity = getPersistentEntity(entity.getClass()); MongoPersistentEntity<?> persistentEntity = getPersistentEntity(entity.getClass());
@ -1286,36 +1279,41 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor(persistentEntity.getPropertyAccessor(entity), ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor(persistentEntity.getPropertyAccessor(entity),
mongoConverter.getConversionService()); mongoConverter.getConversionService());
accessor.setProperty(versionProperty, 0); accessor.setProperty(versionProperty, 0);
return accessor.getBean();
} }
return entity;
} }
@Override @Override
public void insert(Collection<? extends Object> batchToSave, Class<?> entityClass) { public <T> Collection<T> insert(Collection<? extends T> batchToSave, Class<?> entityClass) {
Assert.notNull(batchToSave, "BatchToSave must not be null!"); Assert.notNull(batchToSave, "BatchToSave must not be null!");
doInsertBatch(determineCollectionName(entityClass), batchToSave, this.mongoConverter); return (Collection) doInsertBatch(determineCollectionName(entityClass), batchToSave, this.mongoConverter);
} }
@Override @Override
public void insert(Collection<? extends Object> batchToSave, String collectionName) { public <T> Collection<T> insert(Collection<? extends T> batchToSave, String collectionName) {
Assert.notNull(batchToSave, "BatchToSave must not be null!"); Assert.notNull(batchToSave, "BatchToSave must not be null!");
Assert.notNull(collectionName, "CollectionName must not be null!"); Assert.notNull(collectionName, "CollectionName must not be null!");
doInsertBatch(collectionName, batchToSave, this.mongoConverter); return (Collection) doInsertBatch(collectionName, batchToSave, this.mongoConverter);
} }
@Override @Override
public void insertAll(Collection<? extends Object> objectsToSave) { public <T> Collection<T> insertAll(Collection<? extends T> objectsToSave) {
Assert.notNull(objectsToSave, "ObjectsToSave must not be null!"); Assert.notNull(objectsToSave, "ObjectsToSave must not be null!");
doInsertAll(objectsToSave, this.mongoConverter); return (Collection) doInsertAll(objectsToSave, this.mongoConverter);
} }
protected <T> void doInsertAll(Collection<? extends T> listToSave, MongoWriter<T> writer) { protected <T> Collection<T> doInsertAll(Collection<? extends T> listToSave, MongoWriter<T> writer) {
Map<String, List<T>> elementsByCollection = new HashMap<>(); Map<String, List<T>> elementsByCollection = new HashMap<>();
List<T> savedObjects = new ArrayList<>(listToSave.size());
for (T element : listToSave) { for (T element : listToSave) {
@ -1337,47 +1335,59 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
} }
for (Map.Entry<String, List<T>> entry : elementsByCollection.entrySet()) { for (Map.Entry<String, List<T>> entry : elementsByCollection.entrySet()) {
doInsertBatch(entry.getKey(), entry.getValue(), this.mongoConverter); savedObjects.addAll((Collection) doInsertBatch(entry.getKey(), entry.getValue(), this.mongoConverter));
} }
return savedObjects;
} }
protected <T> void doInsertBatch(String collectionName, Collection<? extends T> batchToSave, MongoWriter<T> writer) { protected <T> Collection<T> doInsertBatch(String collectionName, Collection<? extends T> batchToSave,
MongoWriter<T> writer) {
Assert.notNull(writer, "MongoWriter must not be null!"); Assert.notNull(writer, "MongoWriter must not be null!");
List<Document> documentList = new ArrayList<>(); List<Document> documentList = new ArrayList<>();
for (T o : batchToSave) { List<T> initializedBatchToSave = new ArrayList<>(batchToSave.size());
for (T uninitialized : batchToSave) {
initializeVersionProperty(o); T toSave = (T) initializeVersionProperty(uninitialized);
maybeEmitEvent(new BeforeConvertEvent<>(o, collectionName)); maybeEmitEvent(new BeforeConvertEvent<>(toSave, collectionName));
Document document = toDocument(o, writer); Document document = toDocument(toSave, writer);
maybeEmitEvent(new BeforeSaveEvent<>(o, document, collectionName)); maybeEmitEvent(new BeforeSaveEvent<>(toSave, document, collectionName));
documentList.add(document); documentList.add(document);
initializedBatchToSave.add(toSave);
} }
List<Object> ids = insertDocumentList(collectionName, documentList); List<Object> ids = insertDocumentList(collectionName, documentList);
List<T> savedObjects = new ArrayList<>(documentList.size());
int i = 0; int i = 0;
for (T obj : batchToSave) { for (T obj : initializedBatchToSave) {
if (i < ids.size()) { if (i < ids.size()) {
populateIdIfNecessary(obj, ids.get(i)); T saved = (T) populateIdIfNecessary(obj, ids.get(i));
maybeEmitEvent(new AfterSaveEvent<>(obj, documentList.get(i), collectionName)); maybeEmitEvent(new AfterSaveEvent<>(saved, documentList.get(i), collectionName));
savedObjects.add(saved);
} else {
savedObjects.add(obj);
} }
i++; i++;
} }
return savedObjects;
} }
@Override @Override
public void save(Object objectToSave) { public <T> T save(T objectToSave) {
Assert.notNull(objectToSave, "Object to save must not be null!"); Assert.notNull(objectToSave, "Object to save must not be null!");
save(objectToSave, determineEntityCollectionName(objectToSave)); return save(objectToSave, determineEntityCollectionName(objectToSave));
} }
@Override @Override
public void save(Object objectToSave, String collectionName) { public <T> T save(T objectToSave, String collectionName) {
Assert.notNull(objectToSave, "Object to save must not be null!"); Assert.notNull(objectToSave, "Object to save must not be null!");
Assert.hasText(collectionName, "Collection name must not be null or empty!"); Assert.hasText(collectionName, "Collection name must not be null or empty!");
@ -1385,11 +1395,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
MongoPersistentEntity<?> entity = getPersistentEntity(objectToSave.getClass()); MongoPersistentEntity<?> entity = getPersistentEntity(objectToSave.getClass());
if (entity != null && entity.hasVersionProperty()) { if (entity != null && entity.hasVersionProperty()) {
doSaveVersioned(objectToSave, entity, collectionName); return doSaveVersioned(objectToSave, entity, collectionName);
return;
} }
doSave(collectionName, objectToSave, this.mongoConverter); return (T) doSave(collectionName, objectToSave, this.mongoConverter);
} }
private <T> T doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity, String collectionName) { private <T> T doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity, String collectionName) {
@ -1398,42 +1407,43 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
entity.getPropertyAccessor(objectToSave), mongoConverter.getConversionService()); entity.getPropertyAccessor(objectToSave), mongoConverter.getConversionService());
MongoPersistentProperty property = entity.getRequiredVersionProperty(); MongoPersistentProperty property = entity.getRequiredVersionProperty();
Number number = convertingAccessor.getProperty(property, Number.class); Number number = (Number) convertingAccessor.getProperty(property, Number.class);
if (number != null) { if (number != null) {
// Bump version number // Bump version number
convertingAccessor.setProperty(property, number.longValue() + 1); convertingAccessor.setProperty(property, number.longValue() + 1);
maybeEmitEvent(new BeforeConvertEvent<>(objectToSave, collectionName)); T toSave = (T) convertingAccessor.getBean();
assertUpdateableIdIfNotSet(objectToSave);
maybeEmitEvent(new BeforeConvertEvent<>(toSave, collectionName));
assertUpdateableIdIfNotSet(toSave);
Document document = new Document(); Document document = new Document();
this.mongoConverter.write(objectToSave, document); this.mongoConverter.write(toSave, document);
maybeEmitEvent(new BeforeSaveEvent<>(objectToSave, document, collectionName)); maybeEmitEvent(new BeforeSaveEvent<>(toSave, document, collectionName));
Update update = Update.fromDocument(document, ID_FIELD); Update update = Update.fromDocument(document, ID_FIELD);
// Create query for entity with the id and old version // Create query for entity with the id and old version
MongoPersistentProperty idProperty = entity.getRequiredIdProperty(); MongoPersistentProperty idProperty = entity.getRequiredIdProperty();
Object id = entity.getIdentifierAccessor(objectToSave).getRequiredIdentifier(); Object id = entity.getIdentifierAccessor(toSave).getRequiredIdentifier();
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(property.getName()).is(number)); Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(property.getName()).is(number));
UpdateResult result = doUpdate(collectionName, query, update, objectToSave.getClass(), false, false); UpdateResult result = doUpdate(collectionName, query, update, toSave.getClass(), false, false);
if (result.getModifiedCount() == 0) { if (result.getModifiedCount() == 0) {
throw new OptimisticLockingFailureException( throw new OptimisticLockingFailureException(
String.format("Cannot save entity %s with version %s to collection %s. Has it been modified meanwhile?", id, String.format("Cannot save entity %s with version %s to collection %s. Has it been modified meanwhile?", id,
number, collectionName)); number, collectionName));
} }
maybeEmitEvent(new AfterSaveEvent<>(objectToSave, document, collectionName)); maybeEmitEvent(new AfterSaveEvent<>(toSave, document, collectionName));
return objectToSave; return toSave;
} }
doInsert(collectionName, objectToSave, this.mongoConverter); return (T) doInsert(collectionName, objectToSave, this.mongoConverter);
return objectToSave;
} }
protected <T> T doSave(String collectionName, T objectToSave, MongoWriter<T> writer) { protected <T> T doSave(String collectionName, T objectToSave, MongoWriter<T> writer) {
@ -1446,10 +1456,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
maybeEmitEvent(new BeforeSaveEvent<>(objectToSave, dbDoc, collectionName)); maybeEmitEvent(new BeforeSaveEvent<>(objectToSave, dbDoc, collectionName));
Object id = saveDocument(collectionName, dbDoc, objectToSave.getClass()); Object id = saveDocument(collectionName, dbDoc, objectToSave.getClass());
populateIdIfNecessary(objectToSave, id); T saved = (T) populateIdIfNecessary(objectToSave, id);
maybeEmitEvent(new AfterSaveEvent<>(objectToSave, dbDoc, collectionName)); maybeEmitEvent(new AfterSaveEvent<>(saved, dbDoc, collectionName));
return objectToSave; return saved;
} }
protected Object insertDocument(final String collectionName, final Document document, final Class<?> entityClass) { protected Object insertDocument(final String collectionName, final Document document, final Class<?> entityClass) {
@ -2674,10 +2684,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
* @param id * @param id
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void populateIdIfNecessary(Object savedObject, Object id) { protected Object populateIdIfNecessary(Object savedObject, Object id) {
if (id == null) { if (id == null) {
return; return null;
} }
if (savedObject instanceof Map) { if (savedObject instanceof Map) {
@ -2685,7 +2695,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
Map<String, Object> map = (Map<String, Object>) savedObject; Map<String, Object> map = (Map<String, Object>) savedObject;
map.put(ID_FIELD, id); map.put(ID_FIELD, id);
return; return map;
} }
MongoPersistentProperty idProperty = getIdPropertyFor(savedObject.getClass()); MongoPersistentProperty idProperty = getIdPropertyFor(savedObject.getClass());
@ -2700,7 +2710,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
if (value == null) { if (value == null) {
new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProperty, id); new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProperty, id);
} }
return accessor.getBean();
} }
return savedObject;
} }
private MongoCollection<Document> getAndPrepareCollection(MongoDatabase db, String collectionName) { private MongoCollection<Document> getAndPrepareCollection(MongoDatabase db, String collectionName) {

19
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java

@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.support;
import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Criteria.*;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -77,12 +78,10 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
Assert.notNull(entity, "Entity must not be null!"); Assert.notNull(entity, "Entity must not be null!");
if (entityInformation.isNew(entity)) { if (entityInformation.isNew(entity)) {
mongoOperations.insert(entity, entityInformation.getCollectionName()); return mongoOperations.insert(entity, entityInformation.getCollectionName());
} else {
mongoOperations.save(entity, entityInformation.getCollectionName());
} }
return entity; return mongoOperations.save(entity, entityInformation.getCollectionName());
} }
/* /*
@ -100,13 +99,11 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
if (allNew) { if (allNew) {
List<S> result = source.stream().collect(Collectors.toList()); List<S> result = source.stream().collect(Collectors.toList());
mongoOperations.insert(result, entityInformation.getCollectionName()); return new ArrayList<>(mongoOperations.insert(result, entityInformation.getCollectionName()));
return result; }
} else {
return source.stream().map(this::save).collect(Collectors.toList()); return source.stream().map(this::save).collect(Collectors.toList());
} }
}
/* /*
* (non-Javadoc) * (non-Javadoc)
@ -244,8 +241,7 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
Assert.notNull(entity, "Entity must not be null!"); Assert.notNull(entity, "Entity must not be null!");
mongoOperations.insert(entity, entityInformation.getCollectionName()); return mongoOperations.insert(entity, entityInformation.getCollectionName());
return entity;
} }
/* /*
@ -263,8 +259,7 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
return list; return list;
} }
mongoOperations.insertAll(list); return new ArrayList<>(mongoOperations.insertAll(list));
return list;
} }
/* /*

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

@ -39,6 +39,7 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import lombok.experimental.Wither;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.hamcrest.collection.IsMapContaining; import org.hamcrest.collection.IsMapContaining;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -1638,6 +1639,21 @@ public class MongoTemplateTests {
assertThat(person.version, is(0)); assertThat(person.version, is(0));
} }
@Test // DATAMONGO-1992
public void initializesIdAndVersionAndOfImmutableObject() {
ImmutableVersioned versioned = new ImmutableVersioned();
ImmutableVersioned saved = template.insert(versioned);
assertThat(saved, is(not(sameInstance(versioned))));
assertThat(versioned.id, is(nullValue()));
assertThat(versioned.version, is(nullValue()));
assertThat(saved.id, is(notNullValue()));
assertThat(saved.version, is(0L));
}
@Test(expected = IllegalArgumentException.class) // DATAMONGO-568, DATAMONGO-1762 @Test(expected = IllegalArgumentException.class) // DATAMONGO-568, DATAMONGO-1762
public void queryCantBeNull() { public void queryCantBeNull() {
template.find(null, PersonWithIdPropertyOfTypeObjectId.class); template.find(null, PersonWithIdPropertyOfTypeObjectId.class);
@ -4057,4 +4073,17 @@ public class MongoTemplateTests {
} }
} }
@AllArgsConstructor
@Wither
static class ImmutableVersioned {
final @Id String id;
final @Version Long version;
public ImmutableVersioned() {
id = null;
version = null;
}
}
} }

Loading…
Cancel
Save