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 d6562f75f..bb8406e38 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 abstract class MongoConfigurationSupport { mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder()); mappingContext.setFieldNamingStrategy(fieldNamingStrategy()); + mappingContext.setAutoIndexCreation(autoIndexCreation()); return mappingContext; } @@ -190,4 +191,16 @@ public abstract class MongoConfigurationSupport { 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/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java index 34901303f..640f449cd 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 @@ -3185,6 +3185,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati // 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/IndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexResolver.java index 5bdc8028d..3e7001b0c 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,7 +15,6 @@ */ 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; @@ -36,6 +35,7 @@ public interface IndexResolver { * * @param mappingContext must not be {@literal null}. * @return the new {@link IndexResolver}. + * @since 2.2 */ static IndexResolver create(MongoMappingContext mappingContext) { @@ -51,7 +51,7 @@ public interface IndexResolver { * @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 @@ -61,7 +61,7 @@ public interface IndexResolver { * @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type. * @see 2.2 */ - default Iterable resolveIndexFor(Class entityType) { + 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/JustOnceLogger.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/JustOnceLogger.java new file mode 100644 index 000000000..8b172b007 --- /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/MongoMappingEventPublisher.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java index 6bba8eb8f..0c8fdb415 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,9 +36,7 @@ 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 eeef8af4b..223a625b2 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 @@ -110,6 +110,7 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener) entity); } } @@ -133,8 +134,16 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener 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); + } } } 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 00f19bbd1..c8561fd9c 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 @@ -125,7 +125,12 @@ public class ReactiveMongoPersistentEntityIndexCreator { 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 @@ public class ReactiveMongoPersistentEntityIndexCreator { 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 b69aada3f..0c82b70a6 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 @@ -104,8 +104,9 @@ 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 @@ -116,10 +117,11 @@ public class MongoMappingContext extends AbstractMappingContext + * NOTE:Index creation should happen at a well-defined time that is ideally controlled by the + * application itself. * - * @param autoCreateIndexes {@literal true} to enable auto-index creation. Enabled by default. + * @param autoCreateIndexes set to {@literal false} to disable auto-index creation. * @since 2.2 * @see org.springframework.data.mongodb.core.index.Indexed */ diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java index 0bf973acb..eb0a38b19 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java @@ -42,10 +42,7 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @author Mark Paluch * @author Christoph Strobl - * @deprecated since 2.2. Use {@link org.springframework.data.mongodb.core.index.IndexOperations} to define and create - * indexes. */ -@Deprecated class IndexEnsuringQueryCreationListener implements QueryCreationListener { 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 8795eb976..998500be8 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; - @Deprecated private boolean createIndexesForQueryMethods = false; + private boolean createIndexesForQueryMethods = false; private boolean mappingContextConfigured = false; /** @@ -60,10 +60,7 @@ 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 c44828c0c..277b7d6a7 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,8 +40,7 @@ public class ReactiveMongoRepositoryFactoryBean, S, extends RepositoryFactoryBeanSupport { private @Nullable ReactiveMongoOperations operations; - - @Deprecated private boolean createIndexesForQueryMethods = false; + private boolean createIndexesForQueryMethods = false; private boolean mappingContextConfigured = false; /** @@ -66,10 +65,7 @@ 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 ff8d495db..32b7acd6b 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 @@ -73,7 +73,7 @@ public class IndexingIntegrationTests { assertThat(hasIndex("_firstname", IndexedPerson.class), is(true)); } - @Test // DATAMONGO-237 + @Test // DATAMONGO-2188 @DirtiesContext public void shouldNotCreateIndexOnIndexingDisabled() { 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 6014050bc..e5be79d43 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 @@ -87,12 +87,12 @@ public class MongoPersistentEntityIndexResolverUnitTests { assertIndexPathAndCollection("zero.indexedProperty", "One", indexDefinitions.get(0)); } - @Test // DATAMONGO-899 + @Test // DATAMONGO-899, DATAMONGO-2188 public void shouldResolveIndexViaClass() { MongoMappingContext mappingContext = new MongoMappingContext(); IndexResolver indexResolver = IndexResolver.create(mappingContext); - Iterable definitions = indexResolver.resolveIndexFor(IndexOnLevelOne.class); + Iterable definitions = indexResolver.resolveIndexFor(IndexOnLevelOne.class); assertThat(definitions.iterator().hasNext(), is(true)); } diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index c495b2ef2..2f9710499 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 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`. +[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`. [[mapping-usage-annotations]] === Mapping Annotation Overview