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 19fdbd171..b8acbf5c7 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 @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 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 + * 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, @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - 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; @@ -24,14 +24,29 @@ import java.lang.annotation.Target; /** * Mark a class to use compound indexes. * - * @author Jon Brisbin + * @author Jon Brisbin + * @author Oliver Gierke */ @Target({ ElementType.TYPE }) +@Documented @Retention(RetentionPolicy.RUNTIME) public @interface CompoundIndex { + /** + * The actual index definition in JSON format. The keys of the JSON document are the fields to be indexed, the values + * define the index direction (1 for ascending, -1 for descending). + * + * @return + */ String def(); + /** + * It does not actually make sense to use that attribute as the direction has to be defined in the {@link #def()} + * attribute actually. + * + * @return + */ + @Deprecated IndexDirection direction() default IndexDirection.ASCENDING; boolean unique() default false; @@ -40,8 +55,18 @@ public @interface CompoundIndex { boolean dropDups() default false; + /** + * The name of the index to be created. + * + * @return + */ String name() default ""; + /** + * The collection the index will be created in. Will default to the collection the annotated domain class will be + * stored in. + * + * @return + */ String collection() default ""; - } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java index a2f739fd3..32cb73ae7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreator.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 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 + * 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, @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mongodb.core.index; import java.lang.reflect.Field; @@ -27,7 +26,6 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.event.MappingContextEvent; import org.springframework.data.mongodb.MongoDbFactory; -import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; @@ -39,10 +37,10 @@ import com.mongodb.DBObject; import com.mongodb.util.JSON; /** - * Component that inspects {@link BasicMongoPersistentEntity} instances contained in the given - * {@link MongoMappingContext} for indexing metadata and ensures the indexes to be available. + * Component that inspects {@link MongoPersistentEntity} instances contained in the given {@link MongoMappingContext} + * for indexing metadata and ensures the indexes to be available. * - * @author Jon Brisbin + * @author Jon Brisbin * @author Oliver Gierke */ public class MongoPersistentEntityIndexCreator implements @@ -97,12 +95,12 @@ public class MongoPersistentEntityIndexCreator implements if (type.isAnnotationPresent(CompoundIndexes.class)) { CompoundIndexes indexes = type.getAnnotation(CompoundIndexes.class); for (CompoundIndex index : indexes.value()) { - String indexColl = index.collection(); - if ("".equals(indexColl)) { - indexColl = entity.getCollection(); - } - ensureIndex(indexColl, index.name(), index.def(), index.direction(), index.unique(), index.dropDups(), - index.sparse()); + + String indexColl = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection(); + DBObject definition = (DBObject) JSON.parse(index.def()); + + ensureIndex(indexColl, index.name(), definition, index.unique(), index.dropDups(), index.sparse()); + if (log.isDebugEnabled()) { log.debug("Created compound index " + index); } @@ -111,10 +109,14 @@ public class MongoPersistentEntityIndexCreator implements entity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) { + Field field = persistentProperty.getField(); + if (field.isAnnotationPresent(Indexed.class)) { + Indexed index = field.getAnnotation(Indexed.class); String name = index.name(); + if (!StringUtils.hasText(name)) { name = persistentProperty.getFieldName(); } else { @@ -126,11 +128,17 @@ public class MongoPersistentEntityIndexCreator implements } } } + String collection = StringUtils.hasText(index.collection()) ? index.collection() : entity.getCollection(); - ensureIndex(collection, name, null, index.direction(), index.unique(), index.dropDups(), index.sparse()); + int direction = index.direction() == IndexDirection.ASCENDING ? 1 : -1; + DBObject definition = new BasicDBObject(persistentProperty.getFieldName(), direction); + + ensureIndex(collection, name, definition, index.unique(), index.dropDups(), index.sparse()); + if (log.isDebugEnabled()) { log.debug("Created property index " + index); } + } else if (field.isAnnotationPresent(GeoSpatialIndexed.class)) { GeoSpatialIndexed index = field.getAnnotation(GeoSpatialIndexed.class); @@ -155,21 +163,15 @@ public class MongoPersistentEntityIndexCreator implements } } - protected void ensureIndex(String collection, final String name, final String def, final IndexDirection direction, - final boolean unique, final boolean dropDups, final boolean sparse) { - DBObject defObj; - if (null != def) { - defObj = (DBObject) JSON.parse(def); - } else { - defObj = new BasicDBObject(); - defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1)); - } + protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique, + boolean dropDups, boolean sparse) { + DBObject opts = new BasicDBObject(); opts.put("name", name); opts.put("dropDups", dropDups); opts.put("sparse", sparse); opts.put("unique", unique); - mongoDbFactory.getDb().getCollection(collection).ensureIndex(defObj, opts); - } + mongoDbFactory.getDb().getCollection(collection).ensureIndex(indexDefinition, opts); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java new file mode 100644 index 000000000..b8c8c6533 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012 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 static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.Collections; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; + +import com.mongodb.DBObject; + +/** + * Unit tests for {@link MongoPersistentEntityIndexCreator}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class MongoPersistentEntityIndexCreatorUnitTests { + + @Mock + MongoDbFactory factory; + + @Test + public void buildsIndexDefinitionUsingFieldName() { + + MongoMappingContext mappingContext = new MongoMappingContext(); + mappingContext.setInitialEntitySet(Collections.singleton(Person.class)); + mappingContext.afterPropertiesSet(); + + DummyMongoPersistentEntityIndexCreator creator = new DummyMongoPersistentEntityIndexCreator(mappingContext, factory); + + assertThat(creator.indexDefinition, is(notNullValue())); + assertThat(creator.indexDefinition.keySet(), hasItem("fieldname")); + assertThat(creator.name, is("indexName")); + } + + static class Person { + + @Indexed(name = "indexName") + @Field("fieldname") + String field; + } + + static class DummyMongoPersistentEntityIndexCreator extends MongoPersistentEntityIndexCreator { + + DBObject indexDefinition; + String name; + + public DummyMongoPersistentEntityIndexCreator(MongoMappingContext mappingContext, MongoDbFactory mongoDbFactory) { + super(mappingContext, mongoDbFactory); + } + + @Override + protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique, + boolean dropDups, boolean sparse) { + + this.name = name; + this.indexDefinition = indexDefinition; + } + } +}