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 0fbd88d72..be7c1f8c7 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
@@ -17,12 +17,32 @@ package org.springframework.data.mongodb.core.index;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Mark a class to use compound indexes.
+ *
+ * Some situations may require to have more than one {@link CompoundIndex}. For those scenarios {@link CompoundIndexes}
+ * functions as container annotation for multiple {@link CompoundIndex} annotations via the
+ * {@link CompoundIndexes#value()} or by repeating the {@link CompoundIndex} on the class itself.
+ *
+ *
+ *
+ *
+ * @Document
+ * @CompoundIndex(def = "{'firstname': 1, 'lastname': 1}")
+ * @CompoundIndex(def = "{'address.city': 1, 'address.street': 1}")
+ * class Person {
+ * String firstname;
+ * String lastname;
+ *
+ * Address address;
+ * }
+ *
+ *
*
* @author Jon Brisbin
* @author Oliver Gierke
@@ -32,6 +52,7 @@ import java.lang.annotation.Target;
*/
@Target({ ElementType.TYPE })
@Documented
+@Repeatable(CompoundIndexes.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface CompoundIndex {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndexes.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndexes.java
index cbf6a1bcb..6494a7a73 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndexes.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndexes.java
@@ -15,15 +15,20 @@
*/
package org.springframework.data.mongodb.core.index;
+import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * @author Jon Brisbin
+ * Container annotation that allows to collect multiple {@link CompoundIndex} annotations.
+ *
+ * @author Jon Brisbin
+ * @author Christoph Strobl
*/
@Target({ ElementType.TYPE })
+@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CompoundIndexes {
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 7bac84fe0..0ed371fc7 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
@@ -29,7 +29,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
-
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.annotation.Id;
import org.springframework.data.geo.Point;
@@ -651,6 +650,18 @@ public class MongoPersistentEntityIndexResolverUnitTests {
indexDefinitions.get(0));
}
+ @Test // DATAMONGO-2067
+ public void shouldIdentifyRepeatedAnnotationCorrectly() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(
+ RepeatedCompoundIndex.class);
+
+ assertThat(indexDefinitions).hasSize(2);
+ assertIndexPathAndCollection(new String[] { "firstname", "lastname" }, "repeatedCompoundIndex",
+ indexDefinitions.get(0));
+ assertIndexPathAndCollection(new String[] { "address.city", "address.street" }, "repeatedCompoundIndex", indexDefinitions.get(1));
+ }
+
@Document("CompoundIndexOnLevelOne")
static class CompoundIndexOnLevelOne {
@@ -717,6 +728,10 @@ public class MongoPersistentEntityIndexResolverUnitTests {
@CompoundIndex(def = "#{T(org.bson.Document).parse(\"{ 'foo': 1, 'bar': -1 }\")}")
static class CompoundIndexWithDefExpression {}
+ @Document
+ @CompoundIndex(name = "cmp-idx-one", def = "{'firstname': 1, 'lastname': -1}")
+ @CompoundIndex(name = "cmp-idx-two", def = "{'address.city': -1, 'address.street': 1}")
+ static class RepeatedCompoundIndex {}
}
public static class TextIndexedResolutionTests {
diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc
index 719f4a01a..db2fee0ef 100644
--- a/src/main/asciidoc/reference/mapping.adoc
+++ b/src/main/asciidoc/reference/mapping.adoc
@@ -411,7 +411,7 @@ The MappingMongoConverter can use metadata to drive the mapping of objects to do
* `@Document`: Applied at the class level to indicate this class is a candidate for mapping to the database. You can specify the name of the collection where the database will be stored.
* `@DBRef`: Applied at the field to indicate it is to be stored using a com.mongodb.DBRef.
* `@Indexed`: Applied at the field level to describe how to index the field.
-* `@CompoundIndex`: Applied at the type level to declare Compound Indexes
+* `@CompoundIndex` (repeatable): Applied at the type level to declare Compound Indexes.
* `@GeoSpatialIndexed`: Applied at the field level to describe how to geoindex the field.
* `@TextIndexed`: Applied at the field level to mark the field to be included in the text index.
* `@Language`: Applied at the field level to set the language override property for text index.
@@ -585,6 +585,27 @@ public class Person {
----
====
+[TIP]
+====
+`@CompoundIndex` is a repeatable annotation using `@CompoundIndexes` as the container.
+
+[source,java]
+----
+@Document
+@CompoundIndex(name = "cmp-idx-one", def = "{'firstname': 1, 'lastname': -1}")
+@CompoundIndex(name = "cmp-idx-two", def = "{'address.city': -1, 'address.street': 1}")
+public class Person {
+
+ String firstname;
+ String lastname;
+
+ Address address;
+
+ // ...
+}
+----
+====
+
[[mapping-usage-indexes.text-index]]
=== Text Indexes