diff --git a/pom.xml b/pom.xml
index 79e5353b7f..1a7ae86263 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-GH-4026-SNAPSHOT
pom
Spring Data MongoDB
diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml
index c28a240d2c..3c7d25d0a4 100644
--- a/spring-data-mongodb-benchmarks/pom.xml
+++ b/spring-data-mongodb-benchmarks/pom.xml
@@ -7,7 +7,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-GH-4026-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index 5dedcf81ed..39ad464c63 100644
--- a/spring-data-mongodb-distribution/pom.xml
+++ b/spring-data-mongodb-distribution/pom.xml
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-GH-4026-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index b26a926c7a..08ba67d787 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -12,7 +12,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-GH-4026-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappedDocument.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappedDocument.java
index 7757cbaf88..83552abda7 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappedDocument.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappedDocument.java
@@ -97,6 +97,16 @@ public Document getDocument() {
return this.document;
}
+ /**
+ * Updates the documents {@link #ID_FIELD}.
+ *
+ * @param value the {@literal _id} value to set.
+ * @since 3.4.1
+ */
+ public void updateId(Object value) {
+ document.put(ID_FIELD, value);
+ }
+
/**
* An {@link UpdateDefinition} that indicates that the {@link #getUpdateObject() update object} has already been
* mapped to the specific domain type.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
index 3cce235379..2720a9f57b 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
@@ -30,6 +30,7 @@
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.bson.conversions.Bson;
+import org.bson.types.ObjectId;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -83,6 +84,7 @@
import org.springframework.data.mongodb.core.index.IndexOperationsProvider;
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
+import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
@@ -1392,18 +1394,20 @@ protected Object insertDocument(String collectionName, Document document, Class<
collectionName));
}
+ MappedDocument mappedDocument = queryOperations.createInsertContext(MappedDocument.of(document)).prepareId(entityClass);
+
return execute(collectionName, collection -> {
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName, entityClass,
- document, null);
+ mappedDocument.getDocument(), null);
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
if (writeConcernToUse == null) {
- collection.insertOne(document);
+ collection.insertOne(mappedDocument.getDocument());
} else {
- collection.withWriteConcern(writeConcernToUse).insertOne(document);
+ collection.withWriteConcern(writeConcernToUse).insertOne(mappedDocument.getDocument());
}
- return operations.forEntity(document).getId();
+ return operations.forEntity(mappedDocument.getDocument()).getId();
});
}
@@ -1454,7 +1458,9 @@ protected Object saveDocument(String collectionName, Document dbDoc, Class> en
: collection.withWriteConcern(writeConcernToUse);
if (!mapped.hasId()) {
- collectionToUse.insertOne(dbDoc);
+
+ mapped = queryOperations.createInsertContext(mapped).prepareId(mappingContext.getPersistentEntity(entityClass));
+ collectionToUse.insertOne(mapped.getDocument());
} else {
MongoPersistentEntity> entity = mappingContext.getPersistentEntity(entityClass);
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java
index a8633fcf1e..4254aab66d 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java
@@ -28,7 +28,7 @@
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.codecs.Codec;
-
+import org.bson.types.ObjectId;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.mapping.context.MappingContext;
@@ -46,6 +46,7 @@
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
+import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.ShardKey;
@@ -107,6 +108,14 @@ class QueryOperations {
this.aggregationUtil = new AggregationUtil(queryMapper, mappingContext);
}
+ InsertContext createInsertContext(Document source) {
+ return createInsertContext(MappedDocument.of(source));
+ }
+
+ InsertContext createInsertContext(MappedDocument mappedDocument) {
+ return new InsertContext(mappedDocument);
+ }
+
/**
* Create a new {@link QueryContext} instance.
*
@@ -227,6 +236,57 @@ AggregationDefinition createAggregation(Aggregation aggregation,
return new AggregationDefinition(aggregation, aggregationOperationContext);
}
+ /**
+ * {@link InsertContext} encapsulates common tasks required to interact with {@link Document} to be inserted.
+ *
+ * @since 3.4.1
+ */
+ class InsertContext {
+
+ private final MappedDocument source;
+
+ private InsertContext(MappedDocument source) {
+ this.source = source;
+ }
+
+ /**
+ * Prepare the {@literal _id} field. May generate a new {@literal id} value and convert it to the id properties
+ * {@link MongoPersistentProperty#getFieldType() target type}.
+ *
+ * @param type must not be {@literal null}.
+ * @param
+ * @return the {@link MappedDocument} containing the changes.
+ * @see #prepareId(MongoPersistentEntity)
+ */
+ MappedDocument prepareId(Class type) {
+ return prepareId(mappingContext.getPersistentEntity(type));
+ }
+
+ /**
+ * Prepare the {@literal _id} field. May generate a new {@literal id} value and convert it to the id properties
+ * {@link MongoPersistentProperty#getFieldType() target type}.
+ *
+ * @param entity can be {@literal null}.
+ * @param
+ * @return the {@link MappedDocument} containing the changes.
+ */
+ MappedDocument prepareId(@Nullable MongoPersistentEntity entity) {
+
+ if (entity == null) {
+ return source;
+ }
+
+ MongoPersistentProperty idProperty = entity.getIdProperty();
+ if (idProperty != null
+ && (idProperty.hasExplicitWriteTarget() || idProperty.isAnnotationPresent(MongoId.class))) {
+ if (!ClassUtils.isAssignable(ObjectId.class, idProperty.getFieldType())) {
+ source.updateId(queryMapper.convertId(new ObjectId(), idProperty.getFieldType()));
+ }
+ }
+ return source;
+ }
+ }
+
/**
* {@link QueryContext} encapsulates common tasks required to convert a {@link Query} into its MongoDB document
* representation, mapping field names, as well as determining and applying {@link Collation collations}.
@@ -288,8 +348,7 @@ Document getMappedQuery(@Nullable MongoPersistentEntity entity) {
return queryMapper.getMappedObject(getQueryObject(), entity);
}
- Document getMappedFields(@Nullable MongoPersistentEntity> entity,
- EntityProjection, ?> projection) {
+ Document getMappedFields(@Nullable MongoPersistentEntity> entity, EntityProjection, ?> projection) {
Document fields = evaluateFields(entity);
@@ -402,8 +461,7 @@ private DistinctQueryContext(@Nullable Object query, String fieldName) {
}
@Override
- Document getMappedFields(@Nullable MongoPersistentEntity> entity,
- EntityProjection, ?> projection) {
+ Document getMappedFields(@Nullable MongoPersistentEntity> entity, EntityProjection, ?> projection) {
return getMappedFields(entity);
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
index 67e36d3582..97a5b7a29d 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
@@ -1403,7 +1403,8 @@ protected Mono