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 13c2606e3..94fe71d4c 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 @@ -246,10 +246,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, mappingContext = this.mongoConverter.getMappingContext(); // We create indexes based on mapping events if (mappingContext instanceof MongoMappingContext) { - indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext) mappingContext, this); - eventPublisher = new MongoMappingEventPublisher(indexCreator); - if (mappingContext instanceof ApplicationEventPublisherAware) { - ((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher); + + MongoMappingContext mappingContext = (MongoMappingContext) this.mappingContext; + + if (mappingContext.isAutoIndexCreation()) { + + indexCreator = new MongoPersistentEntityIndexCreator(mappingContext, this); + eventPublisher = new MongoMappingEventPublisher(indexCreator); + mappingContext.setApplicationEventPublisher(eventPublisher); } } } @@ -1582,7 +1586,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, query.getCollation().map(Collation::toMongoCollation).ifPresent(opts::collation); } - Document updateObj = update instanceof MappedUpdate ? update.getUpdateObject() : updateMapper.getMappedObject(update.getUpdateObject(), entity); + Document updateObj = update instanceof MappedUpdate ? update.getUpdateObject() + : updateMapper.getMappedObject(update.getUpdateObject(), entity); if (multi && update.isIsolated() && !queryObj.containsKey("$isolated")) { queryObj.put("$isolated", 1); @@ -1617,7 +1622,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, }); } - private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity persistentEntity, UpdateDefinition update) { + private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity persistentEntity, + UpdateDefinition update) { if (persistentEntity != null && persistentEntity.hasVersionProperty()) { String versionFieldName = persistentEntity.getRequiredVersionProperty().getFieldName(); 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 3e32f780b..34901303f 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 @@ -232,12 +232,15 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati if (this.mappingContext instanceof MongoMappingContext) { MongoMappingContext mongoMappingContext = (MongoMappingContext) this.mappingContext; - this.indexCreator = new ReactiveMongoPersistentEntityIndexCreator(mongoMappingContext, this::indexOps); - this.eventPublisher = new MongoMappingEventPublisher(this.indexCreatorListener); - mongoMappingContext.setApplicationEventPublisher(this.eventPublisher); - this.mappingContext.getPersistentEntities() - .forEach(entity -> onCheckForIndexes(entity, subscriptionExceptionHandler)); + if (mongoMappingContext.isAutoIndexCreation()) { + this.indexCreator = new ReactiveMongoPersistentEntityIndexCreator(mongoMappingContext, this::indexOps); + this.eventPublisher = new MongoMappingEventPublisher(this.indexCreatorListener); + + mongoMappingContext.setApplicationEventPublisher(this.eventPublisher); + this.mappingContext.getPersistentEntities() + .forEach(entity -> onCheckForIndexes(entity, subscriptionExceptionHandler)); + } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java index 3395da3bd..2cac65a39 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java @@ -55,7 +55,8 @@ public @interface CompoundIndex { /** * @return - * @see https://docs.mongodb.org/manual/core/index-unique/ + * @see https://docs.mongodb.org/manual/core/index-unique/ */ boolean unique() default false; @@ -63,13 +64,15 @@ public @interface CompoundIndex { * If set to true index will skip over any document that is missing the indexed field. * * @return - * @see https://docs.mongodb.org/manual/core/index-sparse/ + * @see https://docs.mongodb.org/manual/core/index-sparse/ */ boolean sparse() default false; /** * @return - * @see https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping + * @see https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping * @deprecated since 2.1. No longer supported by MongoDB as of server version 3.0. */ @Deprecated @@ -131,7 +134,8 @@ public @interface CompoundIndex { * If {@literal true} the index will be created in the background. * * @return - * @see https://docs.mongodb.org/manual/core/indexes/#background-construction + * @see https://docs.mongodb.org/manual/core/indexes/#background-construction */ boolean background() default false; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexResolver.java index c1c87ea2a..f2765c246 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexResolver.java @@ -28,8 +28,8 @@ import org.springframework.data.util.TypeInformation; interface IndexResolver { /** - * Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s are created - * for properties and types with {@link Indexed}, {@link CompoundIndexes} or {@link GeoSpatialIndexed}. + * Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s + * are created for properties and types with {@link Indexed}, {@link CompoundIndexes} or {@link GeoSpatialIndexed}. * * @param typeInformation * @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java index 5ecb62d20..d0b253534 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java @@ -31,7 +31,7 @@ import java.lang.annotation.Target; * @author Christoph Strobl * @author Jordi Llach */ -@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD}) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface Indexed { @@ -39,7 +39,8 @@ public @interface Indexed { * If set to true reject all documents that contain a duplicate value for the indexed field. * * @return - * @see https://docs.mongodb.org/manual/core/index-unique/ + * @see https://docs.mongodb.org/manual/core/index-unique/ */ boolean unique() default false; @@ -49,13 +50,15 @@ public @interface Indexed { * If set to true index will skip over any document that is missing the indexed field. * * @return - * @see https://docs.mongodb.org/manual/core/index-sparse/ + * @see https://docs.mongodb.org/manual/core/index-sparse/ */ boolean sparse() default false; /** * @return - * @see https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping + * @see https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping * @deprecated since 2.1. No longer supported by MongoDB as of server version 3.0. */ @Deprecated @@ -115,7 +118,8 @@ public @interface Indexed { * If {@literal true} the index will be created in the background. * * @return - * @see https://docs.mongodb.org/manual/core/indexes/#background-construction + * @see https://docs.mongodb.org/manual/core/indexes/#background-construction */ boolean background() default false; @@ -123,7 +127,8 @@ public @interface Indexed { * Configures the number of seconds after which the collection should expire. Defaults to -1 for no expiry. * * @return - * @see https://docs.mongodb.org/manual/tutorial/expire-data/ + * @see https://docs.mongodb.org/manual/tutorial/expire-data/ */ int expireAfterSeconds() default -1; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java index 0c8fdb415..6bba8eb8f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java @@ -36,7 +36,9 @@ import org.springframework.util.Assert; * @author Jon Brisbin * @author Oliver Gierke * @author Mark Paluch + * @deprecated since 2.2. Use {@link IndexOperations} to define and create indexes. */ +@Deprecated public class MongoMappingEventPublisher implements ApplicationEventPublisher { private final ApplicationListener> indexCreator; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java index c4a7f3f60..80d5966da 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java @@ -63,10 +63,12 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener { private static final Set GEOSPATIAL_TYPES = new HashSet(Arrays.asList(Type.NEAR, Type.WITHIN)); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactoryBean.java index 998500be8..8795eb976 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactoryBean.java @@ -35,7 +35,7 @@ public class MongoRepositoryFactoryBean, S, ID exten extends RepositoryFactoryBeanSupport { private @Nullable MongoOperations operations; - private boolean createIndexesForQueryMethods = false; + @Deprecated private boolean createIndexesForQueryMethods = false; private boolean mappingContextConfigured = false; /** @@ -60,7 +60,10 @@ public class MongoRepositoryFactoryBean, S, ID exten * Configures whether to automatically create indexes for the properties referenced in a query method. * * @param createIndexesForQueryMethods the createIndexesForQueryMethods to set + * @deprecated since 2.2. Use {@link org.springframework.data.mongodb.core.index.IndexOperations} to define and create + * indexes. */ + @Deprecated public void setCreateIndexesForQueryMethods(boolean createIndexesForQueryMethods) { this.createIndexesForQueryMethods = createIndexesForQueryMethods; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java index 277b7d6a7..c44828c0c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java @@ -40,7 +40,8 @@ public class ReactiveMongoRepositoryFactoryBean, S, extends RepositoryFactoryBeanSupport { private @Nullable ReactiveMongoOperations operations; - private boolean createIndexesForQueryMethods = false; + + @Deprecated private boolean createIndexesForQueryMethods = false; private boolean mappingContextConfigured = false; /** @@ -65,7 +66,10 @@ public class ReactiveMongoRepositoryFactoryBean, S, * Configures whether to automatically create indexes for the properties referenced in a query method. * * @param createIndexesForQueryMethods the createIndexesForQueryMethods to set + * @deprecated since 2.2. Use {@link org.springframework.data.mongodb.core.index.IndexOperations} to define and create + * indexes. */ + @Deprecated public void setCreateIndexesForQueryMethods(boolean createIndexesForQueryMethods) { this.createIndexesForQueryMethods = createIndexesForQueryMethods; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexingIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexingIntegrationTests.java index de4d6d52d..ff8d495db 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexingIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexingIntegrationTests.java @@ -30,25 +30,26 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.dao.DataAccessException; +import org.springframework.data.mongodb.MongoCollectionUtils; import org.springframework.data.mongodb.MongoDbFactory; -import org.springframework.data.mongodb.core.CollectionCallback; import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.mongodb.MongoException; -import com.mongodb.client.MongoCollection; - /** * Integration tests for index handling. * * @author Oliver Gierke * @author Christoph Strobl * @author Jordi Llach + * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:infrastructure.xml") @@ -72,6 +73,21 @@ public class IndexingIntegrationTests { assertThat(hasIndex("_firstname", IndexedPerson.class), is(true)); } + @Test // DATAMONGO-237 + @DirtiesContext + public void shouldNotCreateIndexOnIndexingDisabled() { + + MongoMappingContext context = new MongoMappingContext(); + context.setAutoIndexCreation(false); + + MongoTemplate template = new MongoTemplate(mongoDbFactory, + new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context)); + + template.getConverter().getMappingContext().getPersistentEntity(IndexedPerson.class); + + assertThat(hasIndex("_firstname", MongoCollectionUtils.getPreferredCollectionName(IndexedPerson.class)), is(false)); + } + @Test // DATAMONGO-1163 @DirtiesContext public void createsIndexFromMetaAnnotation() { @@ -101,22 +117,30 @@ public class IndexingIntegrationTests { * @param entityType * @return */ - private boolean hasIndex(final String indexName, Class entityType) { + private boolean hasIndex(String indexName, Class entityType) { + return hasIndex(indexName, operations.getCollectionName(entityType)); + } - return operations.execute(entityType, new CollectionCallback() { - public Boolean doInCollection(MongoCollection collection) - throws MongoException, DataAccessException { + /** + * Returns whether an index with the given name exists for the given collection. + * + * @param indexName + * @param collectionName + * @return + */ + private boolean hasIndex(String indexName, String collectionName) { - List indexes = new ArrayList(); - collection.listIndexes(org.bson.Document.class).into(indexes); + return operations.execute(collectionName, collection -> { - for (org.bson.Document indexInfo : indexes) { - if (indexName.equals(indexInfo.get("name"))) { - return true; - } + List indexes = new ArrayList<>(); + collection.listIndexes(org.bson.Document.class).into(indexes); + + for (org.bson.Document indexInfo : indexes) { + if (indexName.equals(indexInfo.get("name"))) { + return true; } - return false; } + return false; }); } } diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index 706d4ec07..c495b2ef2 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -378,7 +378,7 @@ public class Person { IMPORTANT: The `@Id` annotation tells the mapper which property you want to use for the MongoDB `_id` property, and the `@Indexed` annotation tells the mapping framework to call `createIndex(…)` on that property of your document, making searches faster. -IMPORTANT: Automatic index creation is only done for types annotated with `@Document`. +IMPORTANT: Automatic index creation is deprecated since version 2.2 because controlling the actual time of index creation is rather difficult. Index creation can be part of the application startup, happen during runtime or an out of band process. Therefore, Spring Data MongoDB backs off entirely and recommends index creation to happen either out of band or as part of the application startup using `IndexOperations`. Automatic index creation is still available and is is only done for types annotated with `@Document`. [[mapping-usage-annotations]] === Mapping Annotation Overview