Skip to content

Commit 33fa79b

Browse files
mp911dechristophstrobl
authored andcommitted
DATAMONGO-2188 - Deprecate auto-index creation & introduce configuration to disable it.
Auto-index creation can now be disabled by setting MongoMappingContext.setAutoIndexCreation(false). This configuration prevents automatic index creation on application startup and during access to entities. Original Pull Request: #636
1 parent 8f3dacd commit 33fa79b

File tree

13 files changed

+129
-48
lines changed

13 files changed

+129
-48
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,14 @@ public MongoTemplate(MongoDbFactory mongoDbFactory, @Nullable MongoConverter mon
246246
mappingContext = this.mongoConverter.getMappingContext();
247247
// We create indexes based on mapping events
248248
if (mappingContext instanceof MongoMappingContext) {
249-
indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext) mappingContext, this);
250-
eventPublisher = new MongoMappingEventPublisher(indexCreator);
251-
if (mappingContext instanceof ApplicationEventPublisherAware) {
252-
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
249+
250+
MongoMappingContext mappingContext = (MongoMappingContext) this.mappingContext;
251+
252+
if (mappingContext.isAutoIndexCreation()) {
253+
254+
indexCreator = new MongoPersistentEntityIndexCreator(mappingContext, this);
255+
eventPublisher = new MongoMappingEventPublisher(indexCreator);
256+
mappingContext.setApplicationEventPublisher(eventPublisher);
253257
}
254258
}
255259
}
@@ -1582,7 +1586,8 @@ public UpdateResult doInCollection(MongoCollection<Document> collection)
15821586
query.getCollation().map(Collation::toMongoCollation).ifPresent(opts::collation);
15831587
}
15841588

1585-
Document updateObj = update instanceof MappedUpdate ? update.getUpdateObject() : updateMapper.getMappedObject(update.getUpdateObject(), entity);
1589+
Document updateObj = update instanceof MappedUpdate ? update.getUpdateObject()
1590+
: updateMapper.getMappedObject(update.getUpdateObject(), entity);
15861591

15871592
if (multi && update.isIsolated() && !queryObj.containsKey("$isolated")) {
15881593
queryObj.put("$isolated", 1);
@@ -1617,7 +1622,8 @@ public UpdateResult doInCollection(MongoCollection<Document> collection)
16171622
});
16181623
}
16191624

1620-
private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity<?> persistentEntity, UpdateDefinition update) {
1625+
private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity<?> persistentEntity,
1626+
UpdateDefinition update) {
16211627

16221628
if (persistentEntity != null && persistentEntity.hasVersionProperty()) {
16231629
String versionFieldName = persistentEntity.getRequiredVersionProperty().getFieldName();

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,15 @@ public ReactiveMongoTemplate(ReactiveMongoDatabaseFactory mongoDatabaseFactory,
232232
if (this.mappingContext instanceof MongoMappingContext) {
233233

234234
MongoMappingContext mongoMappingContext = (MongoMappingContext) this.mappingContext;
235-
this.indexCreator = new ReactiveMongoPersistentEntityIndexCreator(mongoMappingContext, this::indexOps);
236-
this.eventPublisher = new MongoMappingEventPublisher(this.indexCreatorListener);
237235

238-
mongoMappingContext.setApplicationEventPublisher(this.eventPublisher);
239-
this.mappingContext.getPersistentEntities()
240-
.forEach(entity -> onCheckForIndexes(entity, subscriptionExceptionHandler));
236+
if (mongoMappingContext.isAutoIndexCreation()) {
237+
this.indexCreator = new ReactiveMongoPersistentEntityIndexCreator(mongoMappingContext, this::indexOps);
238+
this.eventPublisher = new MongoMappingEventPublisher(this.indexCreatorListener);
239+
240+
mongoMappingContext.setApplicationEventPublisher(this.eventPublisher);
241+
this.mappingContext.getPersistentEntities()
242+
.forEach(entity -> onCheckForIndexes(entity, subscriptionExceptionHandler));
243+
}
241244
}
242245
}
243246

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,24 @@
5555

5656
/**
5757
* @return
58-
* @see <a href="https://docs.mongodb.org/manual/core/index-unique/">https://docs.mongodb.org/manual/core/index-unique/</a>
58+
* @see <a href=
59+
* "https://docs.mongodb.org/manual/core/index-unique/">https://docs.mongodb.org/manual/core/index-unique/</a>
5960
*/
6061
boolean unique() default false;
6162

6263
/**
6364
* If set to true index will skip over any document that is missing the indexed field.
6465
*
6566
* @return
66-
* @see <a href="https://docs.mongodb.org/manual/core/index-sparse/">https://docs.mongodb.org/manual/core/index-sparse/</a>
67+
* @see <a href=
68+
* "https://docs.mongodb.org/manual/core/index-sparse/">https://docs.mongodb.org/manual/core/index-sparse/</a>
6769
*/
6870
boolean sparse() default false;
6971

7072
/**
7173
* @return
72-
* @see <a href="https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping">https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping</a>
74+
* @see <a href=
75+
* "https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping">https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping</a>
7376
* @deprecated since 2.1. No longer supported by MongoDB as of server version 3.0.
7477
*/
7578
@Deprecated
@@ -131,7 +134,8 @@
131134
* If {@literal true} the index will be created in the background.
132135
*
133136
* @return
134-
* @see <a href="https://docs.mongodb.org/manual/core/indexes/#background-construction">https://docs.mongodb.org/manual/core/indexes/#background-construction</a>
137+
* @see <a href=
138+
* "https://docs.mongodb.org/manual/core/indexes/#background-construction">https://docs.mongodb.org/manual/core/indexes/#background-construction</a>
135139
*/
136140
boolean background() default false;
137141

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
interface IndexResolver {
2929

3030
/**
31-
* Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s are created
32-
* for properties and types with {@link Indexed}, {@link CompoundIndexes} or {@link GeoSpatialIndexed}.
31+
* Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s
32+
* are created for properties and types with {@link Indexed}, {@link CompoundIndexes} or {@link GeoSpatialIndexed}.
3333
*
3434
* @param typeInformation
3535
* @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,16 @@
3131
* @author Christoph Strobl
3232
* @author Jordi Llach
3333
*/
34-
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
34+
@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD })
3535
@Retention(RetentionPolicy.RUNTIME)
3636
public @interface Indexed {
3737

3838
/**
3939
* If set to true reject all documents that contain a duplicate value for the indexed field.
4040
*
4141
* @return
42-
* @see <a href="https://docs.mongodb.org/manual/core/index-unique/">https://docs.mongodb.org/manual/core/index-unique/</a>
42+
* @see <a href=
43+
* "https://docs.mongodb.org/manual/core/index-unique/">https://docs.mongodb.org/manual/core/index-unique/</a>
4344
*/
4445
boolean unique() default false;
4546

@@ -49,13 +50,15 @@
4950
* If set to true index will skip over any document that is missing the indexed field.
5051
*
5152
* @return
52-
* @see <a href="https://docs.mongodb.org/manual/core/index-sparse/">https://docs.mongodb.org/manual/core/index-sparse/</a>
53+
* @see <a href=
54+
* "https://docs.mongodb.org/manual/core/index-sparse/">https://docs.mongodb.org/manual/core/index-sparse/</a>
5355
*/
5456
boolean sparse() default false;
5557

5658
/**
5759
* @return
58-
* @see <a href="https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping">https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping</a>
60+
* @see <a href=
61+
* "https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping">https://docs.mongodb.org/manual/core/index-creation/#index-creation-duplicate-dropping</a>
5962
* @deprecated since 2.1. No longer supported by MongoDB as of server version 3.0.
6063
*/
6164
@Deprecated
@@ -115,15 +118,17 @@
115118
* If {@literal true} the index will be created in the background.
116119
*
117120
* @return
118-
* @see <a href="https://docs.mongodb.org/manual/core/indexes/#background-construction">https://docs.mongodb.org/manual/core/indexes/#background-construction</a>
121+
* @see <a href=
122+
* "https://docs.mongodb.org/manual/core/indexes/#background-construction">https://docs.mongodb.org/manual/core/indexes/#background-construction</a>
119123
*/
120124
boolean background() default false;
121125

122126
/**
123127
* Configures the number of seconds after which the collection should expire. Defaults to -1 for no expiry.
124128
*
125129
* @return
126-
* @see <a href="https://docs.mongodb.org/manual/tutorial/expire-data/">https://docs.mongodb.org/manual/tutorial/expire-data/</a>
130+
* @see <a href=
131+
* "https://docs.mongodb.org/manual/tutorial/expire-data/">https://docs.mongodb.org/manual/tutorial/expire-data/</a>
127132
*/
128133
int expireAfterSeconds() default -1;
129134
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
* @author Jon Brisbin
3737
* @author Oliver Gierke
3838
* @author Mark Paluch
39+
* @deprecated since 2.2. Use {@link IndexOperations} to define and create indexes.
3940
*/
41+
@Deprecated
4042
public class MongoMappingEventPublisher implements ApplicationEventPublisher {
4143

4244
private final ApplicationListener<MappingContextEvent<?, ?>> indexCreator;

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
6363
/**
6464
* Creates a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
6565
* {@link MongoDbFactory}.
66-
* @param mappingContext must not be {@literal null}.
66+
*
67+
* @param mappingContext must not be {@literal null}.
6768
* @param indexOperationsProvider must not be {@literal null}.
6869
*/
69-
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, IndexOperationsProvider indexOperationsProvider) {
70+
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext,
71+
IndexOperationsProvider indexOperationsProvider) {
7072
this(mappingContext, indexOperationsProvider, new MongoPersistentEntityIndexResolver(mappingContext));
7173
}
7274

@@ -78,8 +80,8 @@ public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, Ind
7880
* @param mongoDbFactory must not be {@literal null}.
7981
* @param indexResolver must not be {@literal null}.
8082
*/
81-
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, IndexOperationsProvider indexOperationsProvider,
82-
IndexResolver indexResolver) {
83+
public MongoPersistentEntityIndexCreator(MongoMappingContext mappingContext,
84+
IndexOperationsProvider indexOperationsProvider, IndexResolver indexResolver) {
8385

8486
Assert.notNull(mappingContext, "MongoMappingContext must not be null!");
8587
Assert.notNull(indexOperationsProvider, "IndexOperationsProvider must not be null!");
@@ -146,8 +148,8 @@ void createIndex(IndexDefinitionHolder indexDefinition) {
146148

147149
} catch (UncategorizedMongoDbException ex) {
148150

149-
if (ex.getCause() instanceof MongoException &&
150-
MongoDbErrorCodes.isDataIntegrityViolationCode(((MongoException) ex.getCause()).getCode())) {
151+
if (ex.getCause() instanceof MongoException
152+
&& MongoDbErrorCodes.isDataIntegrityViolationCode(((MongoException) ex.getCause()).getCode())) {
151153

152154
IndexInfo existingIndex = fetchIndexInformation(indexDefinition);
153155
String message = "Cannot create index for '%s' in collection '%s' with keys '%s' and options '%s'.";

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersis
4343

4444
private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY;
4545
private @Nullable ApplicationContext context;
46+
private boolean autoIndexCreation = true;
4647

4748
/**
4849
* Creates a new {@link MongoMappingContext}.
@@ -101,4 +102,28 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
101102

102103
this.context = applicationContext;
103104
}
105+
106+
/**
107+
* Returns whether auto-index creation is enabled or disabled. Please note that auto-index creation is deprecated.
108+
* Index creation should happen at a well-defined time that is ideally controlled by the application itself.
109+
*
110+
* @return {@literal true} when auto-index creation is enabled; {@literal false} otherwise.
111+
* @since 2.2
112+
* @see org.springframework.data.mongodb.core.index.Indexed
113+
*/
114+
public boolean isAutoIndexCreation() {
115+
return autoIndexCreation;
116+
}
117+
118+
/**
119+
* Enables/disables auto-index creation. Please note that auto-index creation is deprecated. Index creation should
120+
* happen at a well-defined time that is ideally controlled by the application its
121+
*
122+
* @param autoCreateIndexes {@literal true} to enable auto-index creation. Enabled by default.
123+
* @since 2.2
124+
* @see org.springframework.data.mongodb.core.index.Indexed
125+
*/
126+
public void setAutoIndexCreation(boolean autoCreateIndexes) {
127+
this.autoIndexCreation = autoCreateIndexes;
128+
}
104129
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@
4242
* @author Oliver Gierke
4343
* @author Mark Paluch
4444
* @author Christoph Strobl
45+
* @deprecated since 2.2. Use {@link org.springframework.data.mongodb.core.index.IndexOperations} to define and create
46+
* indexes.
4547
*/
48+
@Deprecated
4649
class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTreeMongoQuery> {
4750

4851
private static final Set<Type> GEOSPATIAL_TYPES = new HashSet<Type>(Arrays.asList(Type.NEAR, Type.WITHIN));

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
3535
extends RepositoryFactoryBeanSupport<T, S, ID> {
3636

3737
private @Nullable MongoOperations operations;
38-
private boolean createIndexesForQueryMethods = false;
38+
@Deprecated private boolean createIndexesForQueryMethods = false;
3939
private boolean mappingContextConfigured = false;
4040

4141
/**
@@ -60,7 +60,10 @@ public void setMongoOperations(MongoOperations operations) {
6060
* Configures whether to automatically create indexes for the properties referenced in a query method.
6161
*
6262
* @param createIndexesForQueryMethods the createIndexesForQueryMethods to set
63+
* @deprecated since 2.2. Use {@link org.springframework.data.mongodb.core.index.IndexOperations} to define and create
64+
* indexes.
6365
*/
66+
@Deprecated
6467
public void setCreateIndexesForQueryMethods(boolean createIndexesForQueryMethods) {
6568
this.createIndexesForQueryMethods = createIndexesForQueryMethods;
6669
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public class ReactiveMongoRepositoryFactoryBean<T extends Repository<S, ID>, S,
4040
extends RepositoryFactoryBeanSupport<T, S, ID> {
4141

4242
private @Nullable ReactiveMongoOperations operations;
43-
private boolean createIndexesForQueryMethods = false;
43+
44+
@Deprecated private boolean createIndexesForQueryMethods = false;
4445
private boolean mappingContextConfigured = false;
4546

4647
/**
@@ -65,7 +66,10 @@ public void setReactiveMongoOperations(@Nullable ReactiveMongoOperations operati
6566
* Configures whether to automatically create indexes for the properties referenced in a query method.
6667
*
6768
* @param createIndexesForQueryMethods the createIndexesForQueryMethods to set
69+
* @deprecated since 2.2. Use {@link org.springframework.data.mongodb.core.index.IndexOperations} to define and create
70+
* indexes.
6871
*/
72+
@Deprecated
6973
public void setCreateIndexesForQueryMethods(boolean createIndexesForQueryMethods) {
7074
this.createIndexesForQueryMethods = createIndexesForQueryMethods;
7175
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/IndexingIntegrationTests.java

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,26 @@
3030
import org.junit.runner.RunWith;
3131
import org.springframework.beans.factory.annotation.Autowired;
3232
import org.springframework.context.ConfigurableApplicationContext;
33-
import org.springframework.dao.DataAccessException;
33+
import org.springframework.data.mongodb.MongoCollectionUtils;
3434
import org.springframework.data.mongodb.MongoDbFactory;
35-
import org.springframework.data.mongodb.core.CollectionCallback;
3635
import org.springframework.data.mongodb.core.MongoOperations;
36+
import org.springframework.data.mongodb.core.MongoTemplate;
37+
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
38+
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
3739
import org.springframework.data.mongodb.core.mapping.Document;
3840
import org.springframework.data.mongodb.core.mapping.Field;
41+
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
3942
import org.springframework.test.annotation.DirtiesContext;
4043
import org.springframework.test.context.ContextConfiguration;
4144
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
4245

43-
import com.mongodb.MongoException;
44-
import com.mongodb.client.MongoCollection;
45-
4646
/**
4747
* Integration tests for index handling.
4848
*
4949
* @author Oliver Gierke
5050
* @author Christoph Strobl
5151
* @author Jordi Llach
52+
* @author Mark Paluch
5253
*/
5354
@RunWith(SpringJUnit4ClassRunner.class)
5455
@ContextConfiguration("classpath:infrastructure.xml")
@@ -72,6 +73,21 @@ public void createsIndexWithFieldName() {
7273
assertThat(hasIndex("_firstname", IndexedPerson.class), is(true));
7374
}
7475

76+
@Test // DATAMONGO-237
77+
@DirtiesContext
78+
public void shouldNotCreateIndexOnIndexingDisabled() {
79+
80+
MongoMappingContext context = new MongoMappingContext();
81+
context.setAutoIndexCreation(false);
82+
83+
MongoTemplate template = new MongoTemplate(mongoDbFactory,
84+
new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context));
85+
86+
template.getConverter().getMappingContext().getPersistentEntity(IndexedPerson.class);
87+
88+
assertThat(hasIndex("_firstname", MongoCollectionUtils.getPreferredCollectionName(IndexedPerson.class)), is(false));
89+
}
90+
7591
@Test // DATAMONGO-1163
7692
@DirtiesContext
7793
public void createsIndexFromMetaAnnotation() {
@@ -101,22 +117,30 @@ class IndexedPerson {
101117
* @param entityType
102118
* @return
103119
*/
104-
private boolean hasIndex(final String indexName, Class<?> entityType) {
120+
private boolean hasIndex(String indexName, Class<?> entityType) {
121+
return hasIndex(indexName, operations.getCollectionName(entityType));
122+
}
123+
124+
/**
125+
* Returns whether an index with the given name exists for the given collection.
126+
*
127+
* @param indexName
128+
* @param collectionName
129+
* @return
130+
*/
131+
private boolean hasIndex(String indexName, String collectionName) {
105132

106-
return operations.execute(entityType, new CollectionCallback<Boolean>() {
107-
public Boolean doInCollection(MongoCollection<org.bson.Document> collection)
108-
throws MongoException, DataAccessException {
133+
return operations.execute(collectionName, collection -> {
109134

110-
List<org.bson.Document> indexes = new ArrayList<org.bson.Document>();
111-
collection.listIndexes(org.bson.Document.class).into(indexes);
135+
List<org.bson.Document> indexes = new ArrayList<>();
136+
collection.listIndexes(org.bson.Document.class).into(indexes);
112137

113-
for (org.bson.Document indexInfo : indexes) {
114-
if (indexName.equals(indexInfo.get("name"))) {
115-
return true;
116-
}
138+
for (org.bson.Document indexInfo : indexes) {
139+
if (indexName.equals(indexInfo.get("name"))) {
140+
return true;
117141
}
118-
return false;
119142
}
143+
return false;
120144
});
121145
}
122146
}

0 commit comments

Comments
 (0)