diff --git a/pom.xml b/pom.xml
index b6410e6887..544cd5edcd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-mongodb-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-GH-3914-SNAPSHOT
pom
Spring Data MongoDB
diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml
index e2704a6753..c1d664ac19 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
- 3.4.0-SNAPSHOT
+ 3.4.0-GH-3914-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index b75f8bf624..67ae271dcf 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
- 3.4.0-SNAPSHOT
+ 3.4.0-GH-3914-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index ca96626cc9..d8c5170101 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -11,7 +11,7 @@
org.springframework.data
spring-data-mongodb-parent
- 3.4.0-SNAPSHOT
+ 3.4.0-GH-3914-SNAPSHOT
../pom.xml
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 e2137ac047..26503508b7 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
@@ -25,6 +25,15 @@
/**
* {@link IndexResolver} finds those {@link IndexDefinition}s to be created for a given class.
+ *
+ * The {@link IndexResolver} considers index annotations like {@link Indexed}, {@link GeoSpatialIndexed},
+ * {@link HashIndexed}, {@link TextIndexed} and {@link WildcardIndexed} on properties as well as {@link CompoundIndex}
+ * and {@link WildcardIndexed} on types.
+ *
+ * Unless specified otherwise the index name will be created out of the keys/path involved in the index.
+ * {@link TextIndexed} properties are collected into a single index that covers the detected fields.
+ * {@link java.util.Map} like structures, unless annotated with {@link WildcardIndexed}, are skipped because the
+ * {@link java.util.Map.Entry#getKey() map key}, which cannot be resolved from static metadata, needs to be part of the index.
*
* @author Christoph Strobl
* @author Thomas Darimont
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
index 5d773cefc9..baa4b1c36a 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
@@ -158,6 +158,10 @@ private void potentiallyAddIndexForProperty(MongoPersistentEntity> root, Mongo
List indexes, CycleGuard guard) {
try {
+ if (isMapWithoutWildcardIndex(persistentProperty)) {
+ return;
+ }
+
if (persistentProperty.isEntity()) {
indexes.addAll(resolveIndexForEntity(mappingContext.getPersistentEntity(persistentProperty),
persistentProperty.isUnwrapped() ? "" : persistentProperty.getFieldName(), Path.of(persistentProperty),
@@ -220,6 +224,10 @@ private void guardAndPotentiallyAddIndexForProperty(MongoPersistentProperty pers
Path propertyPath = path.append(persistentProperty);
guard.protect(persistentProperty, propertyPath);
+ if (isMapWithoutWildcardIndex(persistentProperty)) {
+ return;
+ }
+
if (persistentProperty.isEntity()) {
try {
indexes.addAll(resolveIndexForEntity(mappingContext.getPersistentEntity(persistentProperty),
@@ -349,6 +357,10 @@ public void doWithPersistentProperty(MongoPersistentProperty persistentProperty)
indexDefinitionBuilder.withLanguageOverride(persistentProperty.getFieldName());
}
+ if(persistentProperty.isMap()) {
+ return;
+ }
+
TextIndexed indexed = persistentProperty.findAnnotation(TextIndexed.class);
if (includeOptions.isForce() || indexed != null || persistentProperty.isEntity()) {
@@ -801,6 +813,10 @@ private static Object evaluate(String value, EvaluationContext evaluationContext
return expression.getValue(evaluationContext, Object.class);
}
+ private static boolean isMapWithoutWildcardIndex(MongoPersistentProperty property) {
+ return property.isMap() && !property.isAnnotationPresent(WildcardIndexed.class);
+ }
+
/**
* {@link CycleGuard} holds information about properties and the paths for accessing those. This information is used
* to detect potential cycles within the references.
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 30f6a9bfc5..b4f1bcd555 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
@@ -1393,6 +1393,15 @@ public void rejectsWildcardProjectionOnNestedPaths() {
});
}
+ @Test // GH-3914
+ public void shouldSkipMapStructuresUnlessAnnotatedWithWildcardIndex() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(
+ WithMapStructures.class);
+
+ assertThat(indexDefinitions).hasSize(1);
+ }
+
@Document
class MixedIndexRoot {
@@ -1626,6 +1635,17 @@ class GenericEntityWrapper {
T entity;
}
+ @Document
+ class WithMapStructures {
+ Map rootMap;
+ NestedInMapWithStructures nested;
+ ValueObject plainValue;
+ }
+
+ class NestedInMapWithStructures {
+ Map nestedMap;
+ }
+
@Document
class EntityWithGenericTypeWrapperAsElement {
List> listWithGeneircTypeElement;
diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc
index e301826697..9ba17cb1f3 100644
--- a/src/main/asciidoc/reference/mapping.adoc
+++ b/src/main/asciidoc/reference/mapping.adoc
@@ -402,12 +402,17 @@ Indexes are automatically created for the initial entity set on application star
We generally recommend explicit index creation for application-based control of indexes as Spring Data cannot automatically create indexes for collections that were recreated while the application was running.
-`IndexResolver` provides an abstraction for programmatic index definition creation if you want to make use of `@Indexed` annotations such as `@GeoSpatialIndexed`, `@TextIndexed`, `@CompoundIndex`.
+`IndexResolver` provides an abstraction for programmatic index definition creation if you want to make use of `@Indexed` annotations such as `@GeoSpatialIndexed`, `@TextIndexed`, `@CompoundIndex` and `@WildcardIndexed`.
You can use index definitions with `IndexOperations` to create indexes.
A good point in time for index creation is on application startup, specifically after the application context was refreshed, triggered by observing `ContextRefreshedEvent`.
This event guarantees that the context is fully initialized.
Note that at this time other components, especially bean factories might have access to the MongoDB database.
+[WARNING]
+===
+`Map` like structures, unless annotated with `@WildcardIndexed`, are skipped by the `IndexResolver` because the _map key_, which cannot be resolved from static metadata, needs to be part of the index definition.
+===
+
.Programmatic Index Creation for a single Domain Type
====
[source,java]