Browse Source

DATAMONGO-2188 - Polishing.

Undo deprecation and transition to configuration option allowing to disable the index creation. Index creation will remain in the codebase as it is used in a lot of places to configure required geo index structures in MongoDB without which query execution would fail.

Original Pull Request: #636
pull/638/head
Christoph Strobl 7 years ago
parent
commit
2f60d08019
  1. 13
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoConfigurationSupport.java
  2. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
  3. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexResolver.java
  4. 84
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/JustOnceLogger.java
  5. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoMappingEventPublisher.java
  6. 11
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java
  7. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/ReactiveMongoPersistentEntityIndexCreator.java
  8. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java
  9. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java
  10. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactoryBean.java
  11. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java
  12. 2
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexingIntegrationTests.java
  13. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java
  14. 23
      src/main/asciidoc/reference/mapping.adoc

13
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.setInitialEntitySet(getInitialEntitySet());
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder()); mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy()); mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
mappingContext.setAutoIndexCreation(autoIndexCreation());
return mappingContext; return mappingContext;
} }
@ -190,4 +191,16 @@ public abstract class MongoConfigurationSupport {
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy()
: PropertyNameFieldNamingStrategy.INSTANCE; : 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. <br />
* <strong>INFO</strong>: As of 3.x the default will be set to {@literal false}.
* @since 2.2
*/
protected boolean autoIndexCreation() {
return true;
}
} }

1
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 // Double check type as Spring infrastructure does not consider nested generics
if (entity instanceof MongoPersistentEntity) { if (entity instanceof MongoPersistentEntity) {
onCheckForIndexes((MongoPersistentEntity<?>) entity, subscriptionExceptionHandler); onCheckForIndexes((MongoPersistentEntity<?>) entity, subscriptionExceptionHandler);
} }
} }

6
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; 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.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation; import org.springframework.data.util.TypeInformation;
@ -36,6 +35,7 @@ public interface IndexResolver {
* *
* @param mappingContext must not be {@literal null}. * @param mappingContext must not be {@literal null}.
* @return the new {@link IndexResolver}. * @return the new {@link IndexResolver}.
* @since 2.2
*/ */
static IndexResolver create(MongoMappingContext mappingContext) { static IndexResolver create(MongoMappingContext mappingContext) {
@ -51,7 +51,7 @@ public interface IndexResolver {
* @param typeInformation * @param typeInformation
* @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type. * @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.
*/ */
Iterable<? extends IndexDefinitionHolder> resolveIndexFor(TypeInformation<?> typeInformation); Iterable<? extends IndexDefinition> resolveIndexFor(TypeInformation<?> typeInformation);
/** /**
* Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s * 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. * @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.
* @see 2.2 * @see 2.2
*/ */
default Iterable<? extends IndexDefinitionHolder> resolveIndexFor(Class<?> entityType) { default Iterable<? extends IndexDefinition> resolveIndexFor(Class<?> entityType) {
return resolveIndexFor(ClassTypeInformation.from(entityType)); return resolveIndexFor(ClassTypeInformation.from(entityType));
} }

84
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<String, Set<String>> 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<String> messages = KNOWN_LOGS.get(loggerName);
if (messages.contains(message)) {
return;
}
messages.add(message);
logger.warn(message);
}
}
}

2
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 Jon Brisbin
* @author Oliver Gierke * @author Oliver Gierke
* @author Mark Paluch * @author Mark Paluch
* @deprecated since 2.2. Use {@link IndexOperations} to define and create indexes.
*/ */
@Deprecated
public class MongoMappingEventPublisher implements ApplicationEventPublisher { public class MongoMappingEventPublisher implements ApplicationEventPublisher {
private final ApplicationListener<MappingContextEvent<?, ?>> indexCreator; private final ApplicationListener<MappingContextEvent<?, ?>> indexCreator;

11
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java

@ -110,6 +110,7 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
// Double check type as Spring infrastructure does not consider nested generics // Double check type as Spring infrastructure does not consider nested generics
if (entity instanceof MongoPersistentEntity) { if (entity instanceof MongoPersistentEntity) {
checkForIndexes((MongoPersistentEntity<?>) entity); checkForIndexes((MongoPersistentEntity<?>) entity);
} }
} }
@ -133,8 +134,16 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
private void checkForAndCreateIndexes(MongoPersistentEntity<?> entity) { private void checkForAndCreateIndexes(MongoPersistentEntity<?> entity) {
if (entity.isAnnotationPresent(Document.class)) { 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); createIndex(indexToCreate);
} }
} }
} }

9
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/ReactiveMongoPersistentEntityIndexCreator.java

@ -125,7 +125,12 @@ public class ReactiveMongoPersistentEntityIndexCreator {
List<Mono<?>> publishers = new ArrayList<>(); List<Mono<?>> publishers = new ArrayList<>();
if (entity.isAnnotationPresent(Document.class)) { 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)); publishers.add(createIndex(indexToCreate));
} }
} }
@ -135,6 +140,8 @@ public class ReactiveMongoPersistentEntityIndexCreator {
Mono<String> createIndex(IndexDefinitionHolder indexDefinition) { Mono<String> createIndex(IndexDefinitionHolder indexDefinition) {
JustOnceLogger.logWarnIndexCreationConfigurationChange(this.getClass().getName());
return operationsProvider.indexOps(indexDefinition.getCollection()).ensureIndex(indexDefinition) // return operationsProvider.indexOps(indexDefinition.getCollection()).ensureIndex(indexDefinition) //
.onErrorResume(ReactiveMongoPersistentEntityIndexCreator::isDataIntegrityViolation, .onErrorResume(ReactiveMongoPersistentEntityIndexCreator::isDataIntegrityViolation,
e -> translateException(e, indexDefinition)); e -> translateException(e, indexDefinition));

12
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java

@ -104,8 +104,9 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
} }
/** /**
* Returns whether auto-index creation is enabled or disabled. Please note that auto-index creation is deprecated. * Returns whether auto-index creation is enabled or disabled. <br />
* Index creation should happen at a well-defined time that is ideally controlled by the application itself. * <strong>NOTE:</strong>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. * @return {@literal true} when auto-index creation is enabled; {@literal false} otherwise.
* @since 2.2 * @since 2.2
@ -116,10 +117,11 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
} }
/** /**
* Enables/disables auto-index creation. Please note that auto-index creation is deprecated. Index creation should * Enables/disables auto-index creation. <br />
* happen at a well-defined time that is ideally controlled by the application its * <strong>NOTE:</strong>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 * @since 2.2
* @see org.springframework.data.mongodb.core.index.Indexed * @see org.springframework.data.mongodb.core.index.Indexed
*/ */

3
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 Oliver Gierke
* @author Mark Paluch * @author Mark Paluch
* @author Christoph Strobl * @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<PartTreeMongoQuery> { class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTreeMongoQuery> {
private static final Set<Type> GEOSPATIAL_TYPES = new HashSet<Type>(Arrays.asList(Type.NEAR, Type.WITHIN)); private static final Set<Type> GEOSPATIAL_TYPES = new HashSet<Type>(Arrays.asList(Type.NEAR, Type.WITHIN));

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactoryBean.java

@ -35,7 +35,7 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
extends RepositoryFactoryBeanSupport<T, S, ID> { extends RepositoryFactoryBeanSupport<T, S, ID> {
private @Nullable MongoOperations operations; private @Nullable MongoOperations operations;
@Deprecated private boolean createIndexesForQueryMethods = false; private boolean createIndexesForQueryMethods = false;
private boolean mappingContextConfigured = false; private boolean mappingContextConfigured = false;
/** /**
@ -60,10 +60,7 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
* Configures whether to automatically create indexes for the properties referenced in a query method. * Configures whether to automatically create indexes for the properties referenced in a query method.
* *
* @param createIndexesForQueryMethods the createIndexesForQueryMethods to set * @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) { public void setCreateIndexesForQueryMethods(boolean createIndexesForQueryMethods) {
this.createIndexesForQueryMethods = createIndexesForQueryMethods; this.createIndexesForQueryMethods = createIndexesForQueryMethods;
} }

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactoryBean.java

@ -40,8 +40,7 @@ public class ReactiveMongoRepositoryFactoryBean<T extends Repository<S, ID>, S,
extends RepositoryFactoryBeanSupport<T, S, ID> { extends RepositoryFactoryBeanSupport<T, S, ID> {
private @Nullable ReactiveMongoOperations operations; private @Nullable ReactiveMongoOperations operations;
private boolean createIndexesForQueryMethods = false;
@Deprecated private boolean createIndexesForQueryMethods = false;
private boolean mappingContextConfigured = false; private boolean mappingContextConfigured = false;
/** /**
@ -66,10 +65,7 @@ public class ReactiveMongoRepositoryFactoryBean<T extends Repository<S, ID>, S,
* Configures whether to automatically create indexes for the properties referenced in a query method. * Configures whether to automatically create indexes for the properties referenced in a query method.
* *
* @param createIndexesForQueryMethods the createIndexesForQueryMethods to set * @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) { public void setCreateIndexesForQueryMethods(boolean createIndexesForQueryMethods) {
this.createIndexesForQueryMethods = createIndexesForQueryMethods; this.createIndexesForQueryMethods = createIndexesForQueryMethods;
} }

2
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)); assertThat(hasIndex("_firstname", IndexedPerson.class), is(true));
} }
@Test // DATAMONGO-237 @Test // DATAMONGO-2188
@DirtiesContext @DirtiesContext
public void shouldNotCreateIndexOnIndexingDisabled() { public void shouldNotCreateIndexOnIndexingDisabled() {

4
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)); assertIndexPathAndCollection("zero.indexedProperty", "One", indexDefinitions.get(0));
} }
@Test // DATAMONGO-899 @Test // DATAMONGO-899, DATAMONGO-2188
public void shouldResolveIndexViaClass() { public void shouldResolveIndexViaClass() {
MongoMappingContext mappingContext = new MongoMappingContext(); MongoMappingContext mappingContext = new MongoMappingContext();
IndexResolver indexResolver = IndexResolver.create(mappingContext); IndexResolver indexResolver = IndexResolver.create(mappingContext);
Iterable<? extends IndexDefinitionHolder> definitions = indexResolver.resolveIndexFor(IndexOnLevelOne.class); Iterable<? extends IndexDefinition> definitions = indexResolver.resolveIndexFor(IndexOnLevelOne.class);
assertThat(definitions.iterator().hasNext(), is(true)); assertThat(definitions.iterator().hasNext(), is(true));
} }

23
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. 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-usage-annotations]]
=== Mapping Annotation Overview === Mapping Annotation Overview

Loading…
Cancel
Save