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