diff --git a/pom.xml b/pom.xml index 657607148e..7aad355338 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2188-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index c2ff37b35c..fcbec2ec6b 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 - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2188-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index fd36f227c0..6d93c83777 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2188-SNAPSHOT ../pom.xml @@ -50,7 +50,7 @@ org.springframework.data spring-data-mongodb - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2188-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index fc8d28a2b6..4ce4ddb459 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2188-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index f3c85a046a..cbe8c93229 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 2.2.0.BUILD-SNAPSHOT + 2.2.0.DATAMONGO-2188-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java index d6562f75fd..bb8406e384 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java @@ -87,6 +87,7 @@ public MongoMappingContext mongoMappingContext() throws ClassNotFoundException { mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder()); mappingContext.setFieldNamingStrategy(fieldNamingStrategy()); + mappingContext.setAutoIndexCreation(autoIndexCreation()); return mappingContext; } @@ -190,4 +191,16 @@ protected FieldNamingStrategy fieldNamingStrategy() { return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() : PropertyNameFieldNamingStrategy.INSTANCE; } + + /** + * Configure whether to automatically create indices for domain types by deriving the + * {@link org.springframework.data.mongodb.core.index.IndexDefinition} from the entity or not. + * + * @return {@literal true} by default.
+ * INFO: As of 3.x the default will be set to {@literal false}. + * @since 2.2 + */ + protected boolean autoIndexCreation() { + return true; + } } 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 13c2606e3e..94fe71d4ca 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 MongoTemplate(MongoDbFactory mongoDbFactory, @Nullable MongoConverter mon 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 UpdateResult doInCollection(MongoCollection collection) 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 UpdateResult doInCollection(MongoCollection collection) }); } - 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 3e32f780b8..640f449cd6 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 ReactiveMongoTemplate(ReactiveMongoDatabaseFactory mongoDatabaseFactory, 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)); + } } } @@ -3182,6 +3185,7 @@ public void onApplicationEvent(MappingContextEvent event) { // Double check type as Spring infrastructure does not consider nested generics if (entity instanceof MongoPersistentEntity) { + onCheckForIndexes((MongoPersistentEntity) 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 3395da3bd5..2cac65a39b 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 @@ /** * @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 @@ * 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 @@ * 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 c1c87ea2a8..0bc0bedc92 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 @@ -15,25 +15,53 @@ */ package org.springframework.data.mongodb.core.index; -import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.util.Assert; /** * {@link IndexResolver} finds those {@link IndexDefinition}s to be created for a given class. * * @author Christoph Strobl * @author Thomas Darimont + * @author Mark Paluch * @since 1.5 */ -interface IndexResolver { +public 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}. + * Creates a new {@link IndexResolver} given {@link MongoMappingContext}. + * + * @param mappingContext must not be {@literal null}. + * @return the new {@link IndexResolver}. + */ + static IndexResolver create(MongoMappingContext mappingContext) { + + Assert.notNull(mappingContext, "MongoMappingContext must not be null!"); + + return new MongoPersistentEntityIndexResolver(mappingContext); + } + + /** + * 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. */ - Iterable resolveIndexFor(TypeInformation typeInformation); + Iterable resolveIndexFor(TypeInformation typeInformation); + + /** + * 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 entityType + * @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type. + * @see 2.2 + */ + default Iterable resolveIndexFor(Class entityType) { + return resolveIndexFor(ClassTypeInformation.from(entityType)); + } } 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 5ecb62d200..d0b2535346 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 @@ * @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 @@ * 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 @@ * 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 @@ * 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 @@ * 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/JustOnceLogger.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/JustOnceLogger.java new file mode 100644 index 0000000000..8b172b007a --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/JustOnceLogger.java @@ -0,0 +1,84 @@ +/* + * Copyright 2019 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 + * + * http://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.index; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Christoph Strobl + * @since 2.2 + */ +class JustOnceLogger { + + private static final Map> KNOWN_LOGS = new ConcurrentHashMap<>(); + private static final String AUTO_INDEX_CREATION_CONFIG_CHANGE; + + static { + AUTO_INDEX_CREATION_CONFIG_CHANGE = "Automatic index creation will be disabled by default as of Spring Data MongoDB 3.x." + + System.lineSeparator() + + "\tPlease use 'MongoMappingContext#setAutoIndexCreation(boolean)' or override 'MongoConfigurationSupport#autoIndexCreation()' to be explicit." + + System.lineSeparator() + + "\tHowever, we recommend setting up indices manually in an application ready block. You may use index derivation there as well." + + System.lineSeparator() + System.lineSeparator() // + + "\t> -----------------------------------------------------------------------------------------" + + System.lineSeparator() // + + "\t> @EventListener(ApplicationReadyEvent.class)" + System.lineSeparator() // + + "\t> public void initIndicesAfterStartup() {" + System.lineSeparator() // + + "\t>" + System.lineSeparator() // + + "\t> IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);" + System.lineSeparator()// + + "\t>" + System.lineSeparator() // + + "\t> IndexResolver resolver = new MongoPersistentEntityIndexResolver(mongoMappingContext);" + + System.lineSeparator() // + + "\t> resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);" + System.lineSeparator() // + + "\t> }" + System.lineSeparator() // + + "\t> -----------------------------------------------------------------------------------------" + + System.lineSeparator(); + } + + static void logWarnIndexCreationConfigurationChange(String loggerName) { + warnOnce(loggerName, AUTO_INDEX_CREATION_CONFIG_CHANGE); + } + + static void warnOnce(String loggerName, String message) { + + Logger logger = LoggerFactory.getLogger(loggerName); + if (!logger.isWarnEnabled()) { + return; + } + + if (!KNOWN_LOGS.containsKey(loggerName)) { + + KNOWN_LOGS.put(loggerName, new ConcurrentSkipListSet<>(Collections.singleton(message))); + logger.warn(message); + } else { + + Set messages = KNOWN_LOGS.get(loggerName); + if (messages.contains(message)) { + return; + } + + messages.add(message); + logger.warn(message); + } + } +} 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 c4a7f3f608..223a625b2e 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,11 +63,13 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener event) { // Double check type as Spring infrastructure does not consider nested generics if (entity instanceof MongoPersistentEntity) { + checkForIndexes((MongoPersistentEntity) entity); } } @@ -131,8 +134,16 @@ private void checkForIndexes(final MongoPersistentEntity entity) { private void checkForAndCreateIndexes(MongoPersistentEntity entity) { if (entity.isAnnotationPresent(Document.class)) { - for (IndexDefinitionHolder indexToCreate : indexResolver.resolveIndexFor(entity.getTypeInformation())) { + for (IndexDefinition indexDefinition : indexResolver.resolveIndexFor(entity.getTypeInformation())) { + + JustOnceLogger.logWarnIndexCreationConfigurationChange(this.getClass().getName()); + + IndexDefinitionHolder indexToCreate = indexDefinition instanceof IndexDefinitionHolder + ? (IndexDefinitionHolder) indexDefinition + : new IndexDefinitionHolder("", indexDefinition, entity.getCollection()); + createIndex(indexToCreate); + } } } @@ -146,8 +157,8 @@ void createIndex(IndexDefinitionHolder indexDefinition) { } catch (UncategorizedMongoDbException ex) { - if (ex.getCause() instanceof MongoException && - MongoDbErrorCodes.isDataIntegrityViolationCode(((MongoException) ex.getCause()).getCode())) { + if (ex.getCause() instanceof MongoException + && MongoDbErrorCodes.isDataIntegrityViolationCode(((MongoException) ex.getCause()).getCode())) { IndexInfo existingIndex = fetchIndexInformation(indexDefinition); String message = "Cannot create index for '%s' in collection '%s' with keys '%s' and options '%s'."; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/ReactiveMongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/ReactiveMongoPersistentEntityIndexCreator.java index 813a8a5040..c8561fd9c2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/ReactiveMongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/ReactiveMongoPersistentEntityIndexCreator.java @@ -63,7 +63,7 @@ public class ReactiveMongoPersistentEntityIndexCreator { */ public ReactiveMongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, ReactiveIndexOperationsProvider operationsProvider) { - this(mappingContext, operationsProvider, new MongoPersistentEntityIndexResolver(mappingContext)); + this(mappingContext, operationsProvider, IndexResolver.create(mappingContext)); } /** @@ -125,7 +125,12 @@ private Mono checkForAndCreateIndexes(MongoPersistentEntity entity) { List> publishers = new ArrayList<>(); if (entity.isAnnotationPresent(Document.class)) { - for (IndexDefinitionHolder indexToCreate : indexResolver.resolveIndexFor(entity.getTypeInformation())) { + for (IndexDefinition indexDefinition : indexResolver.resolveIndexFor(entity.getTypeInformation())) { + + IndexDefinitionHolder indexToCreate = indexDefinition instanceof IndexDefinitionHolder + ? (IndexDefinitionHolder) indexDefinition + : new IndexDefinitionHolder("", indexDefinition, entity.getCollection()); + publishers.add(createIndex(indexToCreate)); } } @@ -135,6 +140,8 @@ private Mono checkForAndCreateIndexes(MongoPersistentEntity entity) { Mono createIndex(IndexDefinitionHolder indexDefinition) { + JustOnceLogger.logWarnIndexCreationConfigurationChange(this.getClass().getName()); + return operationsProvider.indexOps(indexDefinition.getCollection()).ensureIndex(indexDefinition) // .onErrorResume(ReactiveMongoPersistentEntityIndexCreator::isDataIntegrityViolation, e -> translateException(e, indexDefinition)); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java index 49a3d5a942..0c82b70a62 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java @@ -43,6 +43,7 @@ public class MongoMappingContext extends AbstractMappingContext + * NOTE:Index creation should happen at a well-defined time that is ideally controlled by the + * application itself. + * + * @return {@literal true} when auto-index creation is enabled; {@literal false} otherwise. + * @since 2.2 + * @see org.springframework.data.mongodb.core.index.Indexed + */ + public boolean isAutoIndexCreation() { + return autoIndexCreation; + } + + /** + * Enables/disables auto-index creation.
+ * NOTE:Index creation should happen at a well-defined time that is ideally controlled by the + * application itself. + * + * @param autoCreateIndexes set to {@literal false} to disable auto-index creation. + * @since 2.2 + * @see org.springframework.data.mongodb.core.index.Indexed + */ + public void setAutoIndexCreation(boolean autoCreateIndexes) { + this.autoIndexCreation = autoCreateIndexes; + } } 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 de4d6d52de..32b7acd6b5 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.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 void createsIndexWithFieldName() { assertThat(hasIndex("_firstname", IndexedPerson.class), is(true)); } + @Test // DATAMONGO-2188 + @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 @@ class IndexedPerson { * @param entityType * @return */ - private boolean hasIndex(final String indexName, Class entityType) { + private boolean hasIndex(String indexName, Class entityType) { + return hasIndex(indexName, operations.getCollectionName(entityType)); + } + + /** + * 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) { - return operations.execute(entityType, new CollectionCallback() { - public Boolean doInCollection(MongoCollection collection) - throws MongoException, DataAccessException { + return operations.execute(collectionName, collection -> { - List indexes = new ArrayList(); - collection.listIndexes(org.bson.Document.class).into(indexes); + 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; - } + for (org.bson.Document indexInfo : indexes) { + if (indexName.equals(indexInfo.get("name"))) { + return true; } - return false; } + return false; }); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java index 9f1cea4ecb..4c0e4576eb 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java @@ -64,6 +64,7 @@ public class MongoPersistentEntityIndexResolverUnitTests { * Test resolution of {@link Indexed}. * * @author Christoph Strobl + * @author Mark Paluch */ public static class IndexResolutionTests { @@ -87,7 +88,17 @@ public void indexPathOnLevelOneIsResolvedCorrectly() { } @Test // DATAMONGO-899 - public void depplyNestedIndexPathIsResolvedCorrectly() { + public void shouldResolveIndexViaClass() { + + MongoMappingContext mappingContext = new MongoMappingContext(); + IndexResolver indexResolver = IndexResolver.create(mappingContext); + Iterable definitions = indexResolver.resolveIndexFor(IndexOnLevelOne.class); + + assertThat(definitions.iterator().hasNext(), is(true)); + } + + @Test // DATAMONGO-899 + public void deeplyNestedIndexPathIsResolvedCorrectly() { List indexDefinitions = prepareMappingContextAndResolveIndexForType(IndexOnLevelTwo.class); diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index 706d4ec070..05e2e63cf7 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -377,8 +377,29 @@ 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. +Automatic index creation is only done for types annotated with `@Document`. -IMPORTANT: Automatic index creation is only done for types annotated with `@Document`. +[NOTE] +==== +To turn automatic index creation _OFF_ please override `autoIndexCreation()` in your configuration. +[source,java] +---- +@Configuration +public class Config extends AbstractMongoClientConfiguration { + + @Override + public boolean autoIndexCreation() { + return false; + } + + // ... +} +---- +==== + +IMPORTANT: Automatic index creation will be turned _OFF_ by default with the release of 3.x. +We recommend index creation to happen either out of band or as part of the application startup using +`IndexOperations`. We'll once add a `WARN` to your log when we encounter automatic index creation. [[mapping-usage-annotations]] === Mapping Annotation Overview