/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
Java | 3541 lines | 2135 code | 736 blank | 670 comment | 257 complexity | 5371130db57092c99f8e93476fd99e82 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright 2010-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.data.mongodb.core;
- import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
- import java.io.IOException;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.*;
- import java.util.concurrent.TimeUnit;
- import java.util.stream.Collectors;
- import org.bson.Document;
- import org.bson.conversions.Bson;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.context.ApplicationEventPublisher;
- import org.springframework.context.ApplicationEventPublisherAware;
- import org.springframework.context.ApplicationListener;
- import org.springframework.context.ConfigurableApplicationContext;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.ResourceLoader;
- import org.springframework.dao.DataAccessException;
- import org.springframework.dao.InvalidDataAccessApiUsageException;
- import org.springframework.dao.OptimisticLockingFailureException;
- import org.springframework.dao.support.PersistenceExceptionTranslator;
- import org.springframework.data.convert.EntityReader;
- import org.springframework.data.geo.Distance;
- import org.springframework.data.geo.GeoResult;
- import org.springframework.data.geo.GeoResults;
- import org.springframework.data.geo.Metric;
- import org.springframework.data.mapping.MappingException;
- import org.springframework.data.mapping.callback.EntityCallbacks;
- import org.springframework.data.mapping.context.MappingContext;
- import org.springframework.data.mongodb.MongoDatabaseFactory;
- import org.springframework.data.mongodb.MongoDatabaseUtils;
- import org.springframework.data.mongodb.SessionSynchronization;
- import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
- import org.springframework.data.mongodb.core.DefaultBulkOperations.BulkOperationContext;
- import org.springframework.data.mongodb.core.EntityOperations.AdaptibleEntity;
- import org.springframework.data.mongodb.core.QueryOperations.AggregationDefinition;
- import org.springframework.data.mongodb.core.QueryOperations.CountContext;
- import org.springframework.data.mongodb.core.QueryOperations.DeleteContext;
- import org.springframework.data.mongodb.core.QueryOperations.DistinctQueryContext;
- import org.springframework.data.mongodb.core.QueryOperations.QueryContext;
- import org.springframework.data.mongodb.core.QueryOperations.UpdateContext;
- import org.springframework.data.mongodb.core.aggregation.Aggregation;
- import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
- import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
- import org.springframework.data.mongodb.core.aggregation.AggregationResults;
- import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
- import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
- import org.springframework.data.mongodb.core.convert.DbRefResolver;
- 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.IndexOperationsProvider;
- import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
- import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
- import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
- import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
- import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
- import org.springframework.data.mongodb.core.mapping.event.*;
- import org.springframework.data.mongodb.core.mapreduce.GroupBy;
- import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
- import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
- import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
- import org.springframework.data.mongodb.core.query.BasicQuery;
- import org.springframework.data.mongodb.core.query.Collation;
- import org.springframework.data.mongodb.core.query.Criteria;
- import org.springframework.data.mongodb.core.query.Meta;
- import org.springframework.data.mongodb.core.query.Meta.CursorOption;
- import org.springframework.data.mongodb.core.query.NearQuery;
- import org.springframework.data.mongodb.core.query.Query;
- import org.springframework.data.mongodb.core.query.UpdateDefinition;
- import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
- import org.springframework.data.mongodb.core.timeseries.Granularity;
- import org.springframework.data.mongodb.core.validation.Validator;
- import org.springframework.data.mongodb.util.BsonUtils;
- import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
- import org.springframework.data.util.CloseableIterator;
- import org.springframework.data.util.Optionals;
- import org.springframework.lang.Nullable;
- import org.springframework.util.Assert;
- import org.springframework.util.ClassUtils;
- import org.springframework.util.CollectionUtils;
- import org.springframework.util.NumberUtils;
- import org.springframework.util.ObjectUtils;
- import org.springframework.util.ResourceUtils;
- import org.springframework.util.StringUtils;
- import com.mongodb.ClientSessionOptions;
- import com.mongodb.MongoException;
- import com.mongodb.ReadPreference;
- import com.mongodb.WriteConcern;
- import com.mongodb.client.AggregateIterable;
- import com.mongodb.client.ClientSession;
- import com.mongodb.client.DistinctIterable;
- import com.mongodb.client.FindIterable;
- import com.mongodb.client.MapReduceIterable;
- import com.mongodb.client.MongoClient;
- import com.mongodb.client.MongoCollection;
- import com.mongodb.client.MongoCursor;
- import com.mongodb.client.MongoDatabase;
- import com.mongodb.client.MongoIterable;
- import com.mongodb.client.model.*;
- import com.mongodb.client.result.DeleteResult;
- import com.mongodb.client.result.UpdateResult;
- /**
- * Primary implementation of {@link MongoOperations}.
- *
- * @author Thomas Risberg
- * @author Graeme Rocher
- * @author Mark Pollack
- * @author Oliver Gierke
- * @author Amol Nayak
- * @author Patryk Wasik
- * @author Tobias Trelle
- * @author Sebastian Herold
- * @author Thomas Darimont
- * @author Chuong Ngo
- * @author Christoph Strobl
- * @author Doménique Tilleuil
- * @author Niko Schmuck
- * @author Mark Paluch
- * @author Laszlo Csontos
- * @author Maninder Singh
- * @author Borislav Rangelov
- * @author duozhilin
- * @author Andreas Zink
- * @author Cimon Lucas
- * @author Michael J. Simons
- * @author Roman Puchkovskiy
- * @author Yadhukrishna S Pai
- * @author Anton Barkan
- * @author Bartłomiej Mazur
- */
- public class MongoTemplate implements MongoOperations, ApplicationContextAware, IndexOperationsProvider {
- private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class);
- private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE;
- private final MongoConverter mongoConverter;
- private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
- private final MongoDatabaseFactory mongoDbFactory;
- private final PersistenceExceptionTranslator exceptionTranslator;
- private final QueryMapper queryMapper;
- private final UpdateMapper updateMapper;
- private final JsonSchemaMapper schemaMapper;
- private final SpelAwareProxyProjectionFactory projectionFactory;
- private final EntityOperations operations;
- private final PropertyOperations propertyOperations;
- private final QueryOperations queryOperations;
- private @Nullable WriteConcern writeConcern;
- private WriteConcernResolver writeConcernResolver = DefaultWriteConcernResolver.INSTANCE;
- private WriteResultChecking writeResultChecking = WriteResultChecking.NONE;
- private @Nullable ReadPreference readPreference;
- private @Nullable ApplicationEventPublisher eventPublisher;
- private @Nullable EntityCallbacks entityCallbacks;
- private @Nullable ResourceLoader resourceLoader;
- private @Nullable MongoPersistentEntityIndexCreator indexCreator;
- private SessionSynchronization sessionSynchronization = SessionSynchronization.ON_ACTUAL_TRANSACTION;
- /**
- * Constructor used for a basic template configuration.
- *
- * @param mongoClient must not be {@literal null}.
- * @param databaseName must not be {@literal null} or empty.
- * @since 2.1
- */
- public MongoTemplate(MongoClient mongoClient, String databaseName) {
- this(new SimpleMongoClientDatabaseFactory(mongoClient, databaseName), (MongoConverter) null);
- }
- /**
- * Constructor used for a basic template configuration.
- *
- * @param mongoDbFactory must not be {@literal null}.
- */
- public MongoTemplate(MongoDatabaseFactory mongoDbFactory) {
- this(mongoDbFactory, (MongoConverter) null);
- }
- /**
- * Constructor used for a basic template configuration.
- *
- * @param mongoDbFactory must not be {@literal null}.
- * @param mongoConverter
- */
- public MongoTemplate(MongoDatabaseFactory mongoDbFactory, @Nullable MongoConverter mongoConverter) {
- Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
- this.mongoDbFactory = mongoDbFactory;
- this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
- this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter(mongoDbFactory) : mongoConverter;
- this.queryMapper = new QueryMapper(this.mongoConverter);
- this.updateMapper = new UpdateMapper(this.mongoConverter);
- this.schemaMapper = new MongoJsonSchemaMapper(this.mongoConverter);
- this.projectionFactory = new SpelAwareProxyProjectionFactory();
- this.operations = new EntityOperations(this.mongoConverter.getMappingContext());
- this.propertyOperations = new PropertyOperations(this.mongoConverter.getMappingContext());
- this.queryOperations = new QueryOperations(queryMapper, updateMapper, operations, propertyOperations,
- mongoDbFactory);
- // We always have a mapping context in the converter, whether it's a simple one or not
- mappingContext = this.mongoConverter.getMappingContext();
- // We create indexes based on mapping events
- if (mappingContext instanceof MongoMappingContext) {
- MongoMappingContext mappingContext = (MongoMappingContext) this.mappingContext;
- if (mappingContext.isAutoIndexCreation()) {
- indexCreator = new MongoPersistentEntityIndexCreator(mappingContext, this);
- eventPublisher = new MongoMappingEventPublisher(indexCreator);
- mappingContext.setApplicationEventPublisher(eventPublisher);
- }
- }
- }
- private MongoTemplate(MongoDatabaseFactory dbFactory, MongoTemplate that) {
- this.mongoDbFactory = dbFactory;
- this.exceptionTranslator = that.exceptionTranslator;
- this.sessionSynchronization = that.sessionSynchronization;
- // we need to (re)create the MappingMongoConverter as we need to have it use a DbRefResolver that operates within
- // the sames session. Otherwise loading referenced objects would happen outside of it.
- if (that.mongoConverter instanceof MappingMongoConverter) {
- this.mongoConverter = ((MappingMongoConverter) that.mongoConverter).with(dbFactory);
- } else {
- this.mongoConverter = that.mongoConverter;
- }
- this.queryMapper = that.queryMapper;
- this.updateMapper = that.updateMapper;
- this.schemaMapper = that.schemaMapper;
- this.projectionFactory = that.projectionFactory;
- this.mappingContext = that.mappingContext;
- this.operations = that.operations;
- this.propertyOperations = that.propertyOperations;
- this.queryOperations = that.queryOperations;
- }
- /**
- * Configures the {@link WriteResultChecking} to be used with the template. Setting {@literal null} will reset the
- * default of {@link #DEFAULT_WRITE_RESULT_CHECKING}.
- *
- * @param resultChecking
- */
- public void setWriteResultChecking(@Nullable WriteResultChecking resultChecking) {
- this.writeResultChecking = resultChecking == null ? DEFAULT_WRITE_RESULT_CHECKING : resultChecking;
- }
- /**
- * Configures the {@link WriteConcern} to be used with the template. If none is configured the {@link WriteConcern}
- * configured on the {@link MongoDatabaseFactory} will apply.
- *
- * @param writeConcern
- */
- public void setWriteConcern(@Nullable WriteConcern writeConcern) {
- this.writeConcern = writeConcern;
- }
- /**
- * Configures the {@link WriteConcernResolver} to be used with the template.
- *
- * @param writeConcernResolver
- */
- public void setWriteConcernResolver(@Nullable WriteConcernResolver writeConcernResolver) {
- this.writeConcernResolver = writeConcernResolver == null ? DefaultWriteConcernResolver.INSTANCE
- : writeConcernResolver;
- }
- /**
- * Used by @{link {@link #prepareCollection(MongoCollection)} to set the {@link ReadPreference} before any operations
- * are performed.
- *
- * @param readPreference
- */
- public void setReadPreference(@Nullable ReadPreference readPreference) {
- this.readPreference = readPreference;
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
- */
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- prepareIndexCreator(applicationContext);
- eventPublisher = applicationContext;
- if (entityCallbacks == null) {
- setEntityCallbacks(EntityCallbacks.create(applicationContext));
- }
- if (mappingContext instanceof ApplicationEventPublisherAware) {
- ((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
- }
- resourceLoader = applicationContext;
- projectionFactory.setBeanFactory(applicationContext);
- projectionFactory.setBeanClassLoader(applicationContext.getClassLoader());
- }
- /**
- * Set the {@link EntityCallbacks} instance to use when invoking
- * {@link org.springframework.data.mapping.callback.EntityCallback callbacks} like the {@link BeforeSaveCallback}.
- * <br />
- * Overrides potentially existing {@link EntityCallbacks}.
- *
- * @param entityCallbacks must not be {@literal null}.
- * @throws IllegalArgumentException if the given instance is {@literal null}.
- * @since 2.2
- */
- public void setEntityCallbacks(EntityCallbacks entityCallbacks) {
- Assert.notNull(entityCallbacks, "EntityCallbacks must not be null!");
- this.entityCallbacks = entityCallbacks;
- }
- /**
- * Inspects the given {@link ApplicationContext} for {@link MongoPersistentEntityIndexCreator} and those in turn if
- * they were registered for the current {@link MappingContext}. If no creator for the current {@link MappingContext}
- * can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get
- * created appropriately for entity types persisted through this {@link MongoTemplate} instance.
- *
- * @param context must not be {@literal null}.
- */
- private void prepareIndexCreator(ApplicationContext context) {
- String[] indexCreators = context.getBeanNamesForType(MongoPersistentEntityIndexCreator.class);
- for (String creator : indexCreators) {
- MongoPersistentEntityIndexCreator creatorBean = context.getBean(creator, MongoPersistentEntityIndexCreator.class);
- if (creatorBean.isIndexCreatorFor(mappingContext)) {
- return;
- }
- }
- if (context instanceof ConfigurableApplicationContext && indexCreator != null) {
- ((ConfigurableApplicationContext) context).addApplicationListener(indexCreator);
- }
- }
- /**
- * Returns the default {@link org.springframework.data.mongodb.core.convert.MongoConverter}.
- *
- * @return
- */
- public MongoConverter getConverter() {
- return this.mongoConverter;
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
- */
- @Override
- public <T> CloseableIterator<T> stream(Query query, Class<T> entityType) {
- return stream(query, entityType, getCollectionName(entityType));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#stream(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
- */
- @Override
- public <T> CloseableIterator<T> stream(Query query, Class<T> entityType, String collectionName) {
- return doStream(query, entityType, collectionName, entityType);
- }
- @SuppressWarnings("ConstantConditions")
- protected <T> CloseableIterator<T> doStream(Query query, Class<?> entityType, String collectionName,
- Class<T> returnType) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(entityType, "Entity type must not be null!");
- Assert.hasText(collectionName, "Collection name must not be null or empty!");
- Assert.notNull(returnType, "ReturnType must not be null!");
- return execute(collectionName, (CollectionCallback<CloseableIterator<T>>) collection -> {
- MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
- QueryContext queryContext = queryOperations.createQueryContext(query);
- Document mappedQuery = queryContext.getMappedQuery(persistentEntity);
- Document mappedFields = queryContext.getMappedFields(persistentEntity, returnType, projectionFactory);
- FindIterable<Document> cursor = new QueryCursorPreparer(query, entityType).initiateFind(collection,
- col -> col.find(mappedQuery, Document.class).projection(mappedFields));
- return new CloseableIterableCursorAdapter<>(cursor, exceptionTranslator,
- new ProjectingReadCallback<>(mongoConverter, entityType, returnType, collectionName));
- });
- }
- @Override
- public String getCollectionName(Class<?> entityClass) {
- return this.operations.determineCollectionName(entityClass);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(java.lang.String)
- */
- @Override
- @SuppressWarnings("ConstantConditions")
- public Document executeCommand(String jsonCommand) {
- Assert.hasText(jsonCommand, "JsonCommand must not be null nor empty!");
- return execute(db -> db.runCommand(Document.parse(jsonCommand), Document.class));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(org.bson.Document)
- */
- @Override
- @SuppressWarnings("ConstantConditions")
- public Document executeCommand(Document command) {
- Assert.notNull(command, "Command must not be null!");
- return execute(db -> db.runCommand(command, Document.class));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(org.bson.Document, com.mongodb.ReadPreference)
- */
- @Override
- @SuppressWarnings("ConstantConditions")
- public Document executeCommand(Document command, @Nullable ReadPreference readPreference) {
- Assert.notNull(command, "Command must not be null!");
- return execute(db -> readPreference != null //
- ? db.runCommand(command, readPreference, Document.class) //
- : db.runCommand(command, Document.class));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#executeQuery(org.springframework.data.mongodb.core.query.Query, java.lang.String, org.springframework.data.mongodb.core.DocumentCallbackHandler)
- */
- @Override
- public void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch) {
- executeQuery(query, collectionName, dch, new QueryCursorPreparer(query, null));
- }
- /**
- * Execute a MongoDB query and iterate over the query results on a per-document basis with a
- * {@link DocumentCallbackHandler} using the provided CursorPreparer.
- *
- * @param query the query class that specifies the criteria used to find a record and also an optional fields
- * specification, must not be {@literal null}.
- * @param collectionName name of the collection to retrieve the objects from
- * @param documentCallbackHandler the handler that will extract results, one document at a time
- * @param preparer allows for customization of the {@link FindIterable} used when iterating over the result set,
- * (apply limits, skips and so on).
- */
- protected void executeQuery(Query query, String collectionName, DocumentCallbackHandler documentCallbackHandler,
- @Nullable CursorPreparer preparer) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- Assert.notNull(documentCallbackHandler, "DocumentCallbackHandler must not be null!");
- Document queryObject = queryMapper.getMappedObject(query.getQueryObject(), Optional.empty());
- Document sortObject = query.getSortObject();
- Document fieldsObject = query.getFieldsObject();
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Executing query: {} sort: {} fields: {} in collection: {}", serializeToJsonSafely(queryObject),
- sortObject, fieldsObject, collectionName);
- }
- this.executeQueryInternal(new FindCallback(queryObject, fieldsObject, null),
- preparer != null ? preparer : CursorPreparer.NO_OP_PREPARER, documentCallbackHandler, collectionName);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#execute(org.springframework.data.mongodb.core.DbCallback)
- */
- public <T> T execute(DbCallback<T> action) {
- Assert.notNull(action, "DbCallback must not be null!");
- try {
- MongoDatabase db = prepareDatabase(this.doGetDatabase());
- return action.doInDB(db);
- } catch (RuntimeException e) {
- throw potentiallyConvertRuntimeException(e, exceptionTranslator);
- }
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#execute(java.lang.Class, org.springframework.data.mongodb.core.DbCallback)
- */
- public <T> T execute(Class<?> entityClass, CollectionCallback<T> callback) {
- Assert.notNull(entityClass, "EntityClass must not be null!");
- return execute(getCollectionName(entityClass), callback);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#execute(java.lang.String, org.springframework.data.mongodb.core.DbCallback)
- */
- public <T> T execute(String collectionName, CollectionCallback<T> callback) {
- Assert.notNull(collectionName, "CollectionName must not be null!");
- Assert.notNull(callback, "CollectionCallback must not be null!");
- try {
- MongoCollection<Document> collection = getAndPrepareCollection(doGetDatabase(), collectionName);
- return callback.doInCollection(collection);
- } catch (RuntimeException e) {
- throw potentiallyConvertRuntimeException(e, exceptionTranslator);
- }
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#withSession(com.mongodb.ClientSessionOptions)
- */
- @Override
- public SessionScoped withSession(ClientSessionOptions options) {
- Assert.notNull(options, "ClientSessionOptions must not be null!");
- return withSession(() -> mongoDbFactory.getSession(options));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#withSession(com.mongodb.session.ClientSession)
- */
- @Override
- public MongoTemplate withSession(ClientSession session) {
- Assert.notNull(session, "ClientSession must not be null!");
- return new SessionBoundMongoTemplate(session, MongoTemplate.this);
- }
- /**
- * Define if {@link MongoTemplate} should participate in transactions. Default is set to
- * {@link SessionSynchronization#ON_ACTUAL_TRANSACTION}.<br />
- * <strong>NOTE:</strong> MongoDB transactions require at least MongoDB 4.0.
- *
- * @since 2.1
- */
- public void setSessionSynchronization(SessionSynchronization sessionSynchronization) {
- this.sessionSynchronization = sessionSynchronization;
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#createCollection(java.lang.Class)
- */
- public <T> MongoCollection<Document> createCollection(Class<T> entityClass) {
- return createCollection(entityClass, operations.forType(entityClass).getCollectionOptions());
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#createCollection(java.lang.Class, org.springframework.data.mongodb.core.CollectionOptions)
- */
- public <T> MongoCollection<Document> createCollection(Class<T> entityClass,
- @Nullable CollectionOptions collectionOptions) {
- Assert.notNull(entityClass, "EntityClass must not be null!");
- CollectionOptions options = collectionOptions != null ? collectionOptions : CollectionOptions.empty();
- options = Optionals
- .firstNonEmpty(() -> Optional.ofNullable(collectionOptions).flatMap(CollectionOptions::getCollation),
- () -> operations.forType(entityClass).getCollation()) //
- .map(options::collation).orElse(options);
- return doCreateCollection(getCollectionName(entityClass), convertToDocument(options, entityClass));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#createCollection(java.lang.String)
- */
- public MongoCollection<Document> createCollection(String collectionName) {
- Assert.notNull(collectionName, "CollectionName must not be null!");
- return doCreateCollection(collectionName, new Document());
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#createCollection(java.lang.String, org.springframework.data.mongodb.core.CollectionOptions)
- */
- public MongoCollection<Document> createCollection(String collectionName,
- @Nullable CollectionOptions collectionOptions) {
- Assert.notNull(collectionName, "CollectionName must not be null!");
- return doCreateCollection(collectionName, convertToDocument(collectionOptions));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#getCollection(java.lang.String)
- */
- @SuppressWarnings("ConstantConditions")
- public MongoCollection<Document> getCollection(String collectionName) {
- Assert.notNull(collectionName, "CollectionName must not be null!");
- return execute(db -> db.getCollection(collectionName, Document.class));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#getCollection(java.lang.Class)
- */
- public <T> boolean collectionExists(Class<T> entityClass) {
- return collectionExists(getCollectionName(entityClass));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#getCollection(java.lang.String)
- */
- @SuppressWarnings("ConstantConditions")
- public boolean collectionExists(String collectionName) {
- Assert.notNull(collectionName, "CollectionName must not be null!");
- return execute(db -> {
- for (String name : db.listCollectionNames()) {
- if (name.equals(collectionName)) {
- return true;
- }
- }
- return false;
- });
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#dropCollection(java.lang.Class)
- */
- public <T> void dropCollection(Class<T> entityClass) {
- dropCollection(getCollectionName(entityClass));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#dropCollection(java.lang.String)
- */
- public void dropCollection(String collectionName) {
- Assert.notNull(collectionName, "CollectionName must not be null!");
- execute(collectionName, (CollectionCallback<Void>) collection -> {
- collection.drop();
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Dropped collection [{}]",
- collection.getNamespace() != null ? collection.getNamespace().getCollectionName() : collectionName);
- }
- return null;
- });
- }
- @Override
- public IndexOperations indexOps(String collectionName) {
- return indexOps(collectionName, null);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#indexOps(java.lang.String)
- */
- public IndexOperations indexOps(String collectionName, @Nullable Class<?> type) {
- return new DefaultIndexOperations(this, collectionName, type);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#indexOps(java.lang.Class)
- */
- public IndexOperations indexOps(Class<?> entityClass) {
- return indexOps(getCollectionName(entityClass), entityClass);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#bulkOps(org.springframework.data.mongodb.core.BulkMode, java.lang.String)
- */
- public BulkOperations bulkOps(BulkMode bulkMode, String collectionName) {
- return bulkOps(bulkMode, null, collectionName);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#bulkOps(org.springframework.data.mongodb.core.BulkMode, java.lang.Class)
- */
- public BulkOperations bulkOps(BulkMode bulkMode, Class<?> entityClass) {
- return bulkOps(bulkMode, entityClass, getCollectionName(entityClass));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.ExecutableInsertOperation#bulkOps(org.springframework.data.mongodb.core.BulkMode, java.lang.Class, java.lang.String)
- */
- public BulkOperations bulkOps(BulkMode mode, @Nullable Class<?> entityType, String collectionName) {
- Assert.notNull(mode, "BulkMode must not be null!");
- Assert.hasText(collectionName, "Collection name must not be null or empty!");
- DefaultBulkOperations operations = new DefaultBulkOperations(this, collectionName,
- new BulkOperationContext(mode, Optional.ofNullable(getPersistentEntity(entityType)), queryMapper, updateMapper,
- eventPublisher, entityCallbacks));
- operations.setDefaultWriteConcern(writeConcern);
- return operations;
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#scriptOps()
- */
- @Override
- public ScriptOperations scriptOps() {
- return new DefaultScriptOperations(this);
- }
- // Find methods that take a Query to express the query and that return a single object.
- @Nullable
- @Override
- public <T> T findOne(Query query, Class<T> entityClass) {
- return findOne(query, entityClass, getCollectionName(entityClass));
- }
- @Nullable
- @Override
- public <T> T findOne(Query query, Class<T> entityClass, String collectionName) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(entityClass, "EntityClass must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- if (ObjectUtils.isEmpty(query.getSortObject())) {
- return doFindOne(collectionName, query.getQueryObject(), query.getFieldsObject(),
- new QueryCursorPreparer(query, entityClass), entityClass);
- } else {
- query.limit(1);
- List<T> results = find(query, entityClass, collectionName);
- return results.isEmpty() ? null : results.get(0);
- }
- }
- @Override
- public boolean exists(Query query, Class<?> entityClass) {
- return exists(query, entityClass, getCollectionName(entityClass));
- }
- @Override
- public boolean exists(Query query, String collectionName) {
- return exists(query, null, collectionName);
- }
- @Override
- @SuppressWarnings("ConstantConditions")
- public boolean exists(Query query, @Nullable Class<?> entityClass, String collectionName) {
- if (query == null) {
- throw new InvalidDataAccessApiUsageException("Query passed in to exist can't be null");
- }
- Assert.notNull(collectionName, "CollectionName must not be null!");
- QueryContext queryContext = queryOperations.createQueryContext(query);
- Document mappedQuery = queryContext.getMappedQuery(entityClass, this::getPersistentEntity);
- return execute(collectionName,
- new ExistsCallback(mappedQuery, queryContext.getCollation(entityClass).orElse(null)));
- }
- // Find methods that take a Query to express the query and that return a List of objects.
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#findOne(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
- */
- @Override
- public <T> List<T> find(Query query, Class<T> entityClass) {
- return find(query, entityClass, getCollectionName(entityClass));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#findOne(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
- */
- @Override
- public <T> List<T> find(Query query, Class<T> entityClass, String collectionName) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- Assert.notNull(entityClass, "EntityClass must not be null!");
- return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass,
- new QueryCursorPreparer(query, entityClass));
- }
- @Nullable
- @Override
- public <T> T findById(Object id, Class<T> entityClass) {
- return findById(id, entityClass, getCollectionName(entityClass));
- }
- @Nullable
- @Override
- public <T> T findById(Object id, Class<T> entityClass, String collectionName) {
- Assert.notNull(id, "Id must not be null!");
- Assert.notNull(entityClass, "EntityClass must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- String idKey = operations.getIdPropertyName(entityClass);
- return doFindOne(collectionName, new Document(idKey, id), new Document(), entityClass);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#findDistinct(org.springframework.data.mongodb.core.query.Query, java.lang.String, java.lang.Class, java.lang.Class)
- */
- @Override
- public <T> List<T> findDistinct(Query query, String field, Class<?> entityClass, Class<T> resultClass) {
- return findDistinct(query, field, getCollectionName(entityClass), entityClass, resultClass);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#findDistinct(org.springframework.data.mongodb.core.query.Query, java.lang.String, java.lang.String, java.lang.Class, java.lang.Class)
- */
- @Override
- @SuppressWarnings("unchecked")
- public <T> List<T> findDistinct(Query query, String field, String collectionName, Class<?> entityClass,
- Class<T> resultClass) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(field, "Field must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- Assert.notNull(entityClass, "EntityClass must not be null!");
- Assert.notNull(resultClass, "ResultClass must not be null!");
- MongoPersistentEntity<?> entity = entityClass != Object.class ? getPersistentEntity(entityClass) : null;
- DistinctQueryContext distinctQueryContext = queryOperations.distinctQueryContext(query, field);
- Document mappedQuery = distinctQueryContext.getMappedQuery(entity);
- String mappedFieldName = distinctQueryContext.getMappedFieldName(entity);
- Class<T> mongoDriverCompatibleType = distinctQueryContext.getDriverCompatibleClass(resultClass);
- MongoIterable<?> result = execute(collectionName, (collection) -> {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Executing findDistinct using query {} for field: {} in collection: {}",
- serializeToJsonSafely(mappedQuery), field, collectionName);
- }
- QueryCursorPreparer preparer = new QueryCursorPreparer(query, entityClass);
- if (preparer.hasReadPreference()) {
- collection = collection.withReadPreference(preparer.getReadPreference());
- }
- DistinctIterable<T> iterable = collection.distinct(mappedFieldName, mappedQuery, mongoDriverCompatibleType);
- distinctQueryContext.applyCollation(entityClass, iterable::collation);
- return iterable;
- });
- if (resultClass == Object.class || mongoDriverCompatibleType != resultClass) {
- MongoConverter converter = getConverter();
- DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
- result = result.map((source) -> converter.mapValueToTargetType(source,
- distinctQueryContext.getMostSpecificConversionTargetType(resultClass, entityClass), dbRefResolver));
- }
- try {
- return (List<T>) result.into(new ArrayList<>());
- } catch (RuntimeException e) {
- throw potentiallyConvertRuntimeException(e, exceptionTranslator);
- }
- }
- @Override
- public <T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass) {
- return geoNear(near, entityClass, getCollectionName(entityClass));
- }
- @Override
- public <T> GeoResults<T> geoNear(NearQuery near, Class<T> domainType, String collectionName) {
- return geoNear(near, domainType, collectionName, domainType);
- }
- public <T> GeoResults<T> geoNear(NearQuery near, Class<?> domainType, String collectionName, Class<T> returnType) {
- if (near == null) {
- throw new InvalidDataAccessApiUsageException("NearQuery must not be null!");
- }
- if (domainType == null) {
- throw new InvalidDataAccessApiUsageException("Entity class must not be null!");
- }
- Assert.notNull(collectionName, "CollectionName must not be null!");
- Assert.notNull(returnType, "ReturnType must not be null!");
- String collection = StringUtils.hasText(collectionName) ? collectionName : getCollectionName(domainType);
- String distanceField = operations.nearQueryDistanceFieldName(domainType);
- Aggregation $geoNear = TypedAggregation.newAggregation(domainType, Aggregation.geoNear(near, distanceField))
- .withOptions(AggregationOptions.builder().collation(near.getCollation()).build());
- AggregationResults<Document> results = aggregate($geoNear, collection, Document.class);
- DocumentCallback<GeoResult<T>> callback = new GeoNearResultDocumentCallback<>(distanceField,
- new ProjectingReadCallback<>(mongoConverter, domainType, returnType, collection), near.getMetric());
- List<GeoResult<T>> result = new ArrayList<>();
- BigDecimal aggregate = BigDecimal.ZERO;
- for (Document element : results) {
- GeoResult<T> geoResult = callback.doWith(element);
- aggregate = aggregate.add(BigDecimal.valueOf(geoResult.getDistance().getValue()));
- result.add(geoResult);
- }
- Distance avgDistance = new Distance(
- result.size() == 0 ? 0 : aggregate.divide(new BigDecimal(result.size()), RoundingMode.HALF_UP).doubleValue(),
- near.getMetric());
- return new GeoResults<>(result, avgDistance);
- }
- @Nullable
- @Override
- public <T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass) {
- return findAndModify(query, update, new FindAndModifyOptions(), entityClass, getCollectionName(entityClass));
- }
- @Nullable
- @Override
- public <T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass, String collectionName) {
- return findAndModify(query, update, new FindAndModifyOptions(), entityClass, collectionName);
- }
- @Nullable
- @Override
- public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass) {
- return findAndModify(query, update, options, entityClass, getCollectionName(entityClass));
- }
- @Nullable
- @Override
- public <T> T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, Class<T> entityClass,
- String collectionName) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(update, "Update must not be null!");
- Assert.notNull(options, "Options must not be null!");
- Assert.notNull(entityClass, "EntityClass must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- FindAndModifyOptions optionsToUse = FindAndModifyOptions.of(options);
- Optionals.ifAllPresent(query.getCollation(), optionsToUse.getCollation(), (l, r) -> {
- throw new IllegalArgumentException(
- "Both Query and FindAndModifyOptions define a collation. Please provide the collation only via one of the two.");
- });
- if (!options.getCollation().isPresent()) {
- operations.forType(entityClass).getCollation(query).ifPresent(optionsToUse::collation);
- }
- return doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(),
- getMappedSortObject(query, entityClass), entityClass, update, optionsToUse);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#findAndReplace(org.springframework.data.mongodb.core.query.Query, java.lang.Object, org.springframework.data.mongodb.core.FindAndReplaceOptions, java.lang.Class, java.lang.String, java.lang.Class)
- */
- @Override
- public <S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class<S> entityType,
- String collectionName, Class<T> resultType) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(replacement, "Replacement must not be null!");
- Assert.notNull(options, "Options must not be null! Use FindAndReplaceOptions#empty() instead.");
- Assert.notNull(entityType, "EntityType must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- Assert.notNull(resultType, "ResultType must not be null! Use Object.class instead.");
- Assert.isTrue(query.getLimit() <= 1, "Query must not define a limit other than 1 ore none!");
- Assert.isTrue(query.getSkip() <= 0, "Query must not define skip.");
- MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
- QueryContext queryContext = queryOperations.createQueryContext(query);
- Document mappedQuery = queryContext.getMappedQuery(entity);
- Document mappedFields = queryContext.getMappedFields(entity, resultType, projectionFactory);
- Document mappedSort = queryContext.getMappedSort(entity);
- replacement = maybeCallBeforeConvert(replacement, collectionName);
- Document mappedReplacement = operations.forEntity(replacement).toMappedDocument(this.mongoConverter).getDocument();
- maybeEmitEvent(new BeforeSaveEvent<>(replacement, mappedReplacement, collectionName));
- maybeCallBeforeSave(replacement, mappedReplacement, collectionName);
- T saved = doFindAndReplace(collectionName, mappedQuery, mappedFields, mappedSort,
- queryContext.getCollation(entityType).orElse(null), entityType, mappedReplacement, options, resultType);
- if (saved != null) {
- maybeEmitEvent(new AfterSaveEvent<>(saved, mappedReplacement, collectionName));
- return maybeCallAfterSave(saved, mappedReplacement, collectionName);
- }
- return saved;
- }
- // Find methods that take a Query to express the query and that return a single object that is also removed from the
- // collection in the database.
- @Nullable
- @Override
- public <T> T findAndRemove(Query query, Class<T> entityClass) {
- return findAndRemove(query, entityClass, getCollectionName(entityClass));
- }
- @Nullable
- @Override
- public <T> T findAndRemove(Query query, Class<T> entityClass, String collectionName) {
- Assert.notNull(query, "Query must not be null!");
- Assert.notNull(entityClass, "EntityClass must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- return doFindAndRemove(collectionName, query.getQueryObject(), query.getFieldsObject(),
- getMappedSortObject(query, entityClass), operations.forType(entityClass).getCollation(query).orElse(null),
- entityClass);
- }
- @Override
- public long count(Query query, Class<?> entityClass) {
- Assert.notNull(entityClass, "Entity class must not be null!");
- return count(query, entityClass, getCollectionName(entityClass));
- }
- @Override
- public long count(Query query, String collectionName) {
- return count(query, null, collectionName);
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
- */
- public long count(Query query, @Nullable Class<?> entityClass, String collectionName) {
- Assert.notNull(query, "Query must not be null!");
- Assert.hasText(collectionName, "Collection name must not be null or empty!");
- CountContext countContext = queryOperations.countQueryContext(query);
- CountOptions options = countContext.getCountOptions(entityClass);
- Document mappedQuery = countContext.getMappedQuery(entityClass, mappingContext::getPersistentEntity);
- return doCount(collectionName, mappedQuery, options);
- }
- @SuppressWarnings("ConstantConditions")
- protected long doCount(String collectionName, Document filter, CountOptions options) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Executing count: {} in collection: {}", serializeToJsonSafely(filter), collectionName);
- }
- return execute(collectionName,
- collection -> collection.countDocuments(CountQuery.of(filter).toQueryDocument(), options));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#estimatedCount(java.lang.String)
- */
- @Override
- public long estimatedCount(String collectionName) {
- return doEstimatedCount(collectionName, new EstimatedDocumentCountOptions());
- }
- protected long doEstimatedCount(String collectionName, EstimatedDocumentCountOptions options) {
- return execute(collectionName, collection -> collection.estimatedDocumentCount(options));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object)
- */
- @Override
- public <T> T insert(T objectToSave) {
- Assert.notNull(objectToSave, "ObjectToSave must not be null!");
- ensureNotIterable(objectToSave);
- return insert(objectToSave, getCollectionName(ClassUtils.getUserClass(objectToSave)));
- }
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object, java.lang.String)
- */
- @Override
- @SuppressWarnings("unchecked")
- public <T> T insert(T objectToSave, String collectionName) {
- Assert.notNull(objectToSave, "ObjectToSave must not be null!");
- Assert.notNull(collectionName, "CollectionName must not be null!");
- ensureNotIterable(objectToSave);
- return (T) doInsert(collectionName, objectToSave, this.mongoConverter);
- }
- /**
- * Ensure the given {@literal source} is not an {@link java.lang.reflect.Array}, {@link Collection} or
- * {@link Iterator}.
- *
- * @param source can be {@literal null}.
- * @deprecated since 3.2. Call {@link #ensureNotCollectionLike(Object)} instead.
- */
- protected void ensureNotIterable(@Nullable Object source) {
- ensureNotCollectionLike(source);
- }
- /**
- * Ensure the given {@literal source} is not an {@link java.lang.reflect.Array}, {@link Collection} or
- * {@link Iterator}.
- *
- * @param source can be {@literal null}.
- * @since 3.2.
- */
- protected void ensureNotCollectionLike(@Nullable Object source) {
- if (EntityOperations.isCollectionLike(source)) {
- throw new IllegalArgumentException("Cannot use a collection here.");
- }
- }
- /**
- * Prepare the collection before any processing is done using it. This allows a convenient way to apply settings like
- * withCodecRegistry() etc. Can be overridden in sub-classes.
- *
- * @param collection
- */
- protected MongoCollection<Document> prepareCollection(MongoCollection<Document> collection) {
- if (this.readPreference != null) {
- collection = collection.withReadPreference(readPreference);
- }
- return collection;
- }
- /**
- * Prepare the WriteConcern before any processing is done using it. This allows a convenient way to apply custom
- * settings in sub-classes. <br />
- * In case of using MongoDB Java driver version 3 the returned {@link WriteConcern} will be defaulted to
- * {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}.
- *
- * @param mongoAction any MongoAction already configured or null
- * @return The prepared WriteConcern or null
- */
- @Nullable
- protected WriteConcern prepareWriteConcern(MongoAction mongoAction) {
- WriteConcern wc = writeConcernResolver.resolve(mongoAction);
- return potentiallyForceAcknowledgedWrite(wc);
- }
- @Nullable
- private WriteConcern potentiallyForceAcknowledgedWrite(@Nullable WriteConcern wc) {
- if (ObjectUtils.nullSafeEquals(WriteResultChecking.EXCEPTION, writeResultChecking)) {
- if (wc == null || wc.getWObject() == null
- || (wc.getWObject() instanceof Number && ((Number) wc.getWObject()).intValue() < 1)) {
- return WriteConcern.ACKNOWLEDGED;
- }
- }
- return wc;
- }
- protected <T> T doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
- BeforeConvertEvent<T> event = new BeforeConvertEvent<>(objectToSave, collectionName);
- T toConvert = maybeEmitEvent(event).getSource();
- toConvert = maybeCallBeforeConvert(toConvert, collectionName);
- AdaptibleEntity<T> entity = operations.forEntity(toConvert, mongoConverter.getConversionService());
- entity.assertUpdateableIdIfNotSet();
- T initialized = entity.initializeVersionProperty();
- Document dbDoc = entity.toMappedDocument(writer).getDocument();
- maybeEmitEvent(new BeforeSaveEvent<>(initialized, dbDoc, collectionName));
- initialized = maybeCallBeforeSave(initialized, dbDoc, collectionName);
- Object id = insertDocument(collectionName, dbDoc, initialized.getClass());
- T saved = populateIdIfNecessary(initialized, id);
- maybeEmitEvent(new AfterSaveEvent<>(saved, dbDoc, collectionName));
- return maybeCallAfterSave(saved, dbDoc, collectionName);
- }
- @Override
- @SuppressWarnings("unchecked")
- public <T> Collection…
Large files files are truncated, but you can click here to view the full file