From 13a69ecdfdd6e33c283f2cd1b3af5f2ff7c33d4b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 7 Sep 2012 21:11:59 +0200 Subject: [PATCH] DATAMONGO-533 - Fixed index creator registration. In cases an ApplicationContext already contains a MongoPersistentEntityIndexCreator the default one is not registered, even if the one in the ApplicationContext listens to another MappingContext's events. Polished iterable classes setup in MongoTemplate along the way. Some JavaDoc polishes as well. --- .../data/mongodb/core/MongoTemplate.java | 55 +++++++++++++++---- .../MongoPersistentEntityIndexCreator.java | 21 +++++++ .../mongodb/core/MongoTemplateUnitTests.java | 32 ++++++++++- ...entEntityIndexCreatorIntegrationTests.java | 4 +- ...PersistentEntityIndexCreatorUnitTests.java | 14 +++++ 5 files changed, 110 insertions(+), 16 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 643602c3b..e8e9dba85 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -113,14 +114,17 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(MongoTemplate.class); private static final String ID = "_id"; private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE; - @SuppressWarnings("serial") - private static final List ITERABLE_CLASSES = new ArrayList() { - { - add(List.class.getName()); - add(Collection.class.getName()); - add(Iterator.class.getName()); - } - }; + private static final Collection ITERABLE_CLASSES; + + static { + + Set iterableClasses = new HashSet(); + iterableClasses.add(List.class.getName()); + iterableClasses.add(Collection.class.getName()); + iterableClasses.add(Iterator.class.getName()); + + ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses); + } /* * WriteConcern to be used for write operations if it has been specified. @@ -247,11 +251,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { this.readPreference = readPreference; } + /* + * (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - String[] beans = applicationContext.getBeanNamesForType(MongoPersistentEntityIndexCreator.class); - if ((null == beans || beans.length == 0) && applicationContext instanceof ConfigurableApplicationContext) { - ((ConfigurableApplicationContext) applicationContext).addApplicationListener(indexCreator); - } + + prepareIndexCreator(applicationContext); + eventPublisher = applicationContext; if (mappingContext instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher); @@ -259,6 +266,30 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware { resourceLoader = applicationContext; } + /** + * Inspects the given {@link ApplicationContext} for {@link MongoPersistentEntityIndexCreator} and those in turn if + * they were registered for the current {@link MappingContext}. If no creator for the current {@link MappingContext} + * can be found we manually add the internally created one as {@link ApplicationListener} to make sure indexes get + * created appropriately for entity types persisted through this {@link MongoTemplate} instance. + * + * @param context + */ + private void prepareIndexCreator(ApplicationContext context) { + + String[] indexCreators = context.getBeanNamesForType(MongoPersistentEntityIndexCreator.class); + + for (String creator : indexCreators) { + MongoPersistentEntityIndexCreator creatorBean = context.getBean(creator, MongoPersistentEntityIndexCreator.class); + if (creatorBean.isIndexCreatorFor(mappingContext)) { + return; + } + } + + if (context instanceof ConfigurableApplicationContext) { + ((ConfigurableApplicationContext) context).addApplicationListener(indexCreator); + } + } + /** * Returns the default {@link org.springframework.data.mongodb.core.core.convert.MongoConverter}. * 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 84c342d1f..6d78a5e76 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 @@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationListener; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PropertyHandler; +import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContextEvent; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @@ -169,6 +170,26 @@ public class MongoPersistentEntityIndexCreator implements } } + /** + * Returns whether the current index creator was registered for the given {@link MappingContext}. + * + * @param context + * @return + */ + public boolean isIndexCreatorFor(MappingContext context) { + return this.mappingContext.equals(context); + } + + /** + * Triggers the actual index creation. + * + * @param collection the collection to create the index in + * @param name the name of the index about to be created + * @param indexDefinition the index definition + * @param unique whether it shall be a unique index + * @param dropDups whether to drop duplicates + * @param sparse sparse or not + */ protected void ensureIndex(String collection, String name, DBObject indexDefinition, boolean unique, boolean dropDups, boolean sparse) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index b972c24e0..ae08ed5ea 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -15,12 +15,13 @@ */ package org.springframework.data.mongodb.core; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import java.math.BigInteger; +import java.util.Collection; import java.util.Collections; import java.util.regex.Pattern; @@ -31,6 +32,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.context.ApplicationListener; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; @@ -40,6 +42,7 @@ import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.convert.CustomConversions; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.convert.QueryMapper; +import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; @@ -71,11 +74,13 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { DBCollection collection; MappingMongoConverter converter; + MongoMappingContext mappingContext; @Before public void setUp() { - this.converter = new MappingMongoConverter(factory, new MongoMappingContext()); + this.mappingContext = new MongoMappingContext(); + this.converter = new MappingMongoConverter(factory, mappingContext); this.template = new MongoTemplate(factory, converter); when(factory.getDb()).thenReturn(db); @@ -198,6 +203,29 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { assertThat(entity.id, is(5)); } + /** + * @see DATAMONGO-533 + */ + @Test + public void registersDefaultEntityIndexCreatorIfApplicationContextHasOneForDifferentMappingContext() { + + GenericApplicationContext applicationContext = new GenericApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("foo", + new MongoPersistentEntityIndexCreator(new MongoMappingContext(), factory)); + + MongoTemplate mongoTemplate = new MongoTemplate(factory, converter); + mongoTemplate.setApplicationContext(applicationContext); + + Collection> listeners = applicationContext.getApplicationListeners(); + assertThat(listeners, hasSize(1)); + + ApplicationListener listener = listeners.iterator().next(); + + assertThat(listener, is(instanceOf(MongoPersistentEntityIndexCreator.class))); + MongoPersistentEntityIndexCreator creator = (MongoPersistentEntityIndexCreator) listener; + assertThat(creator.isIndexCreatorFor(mappingContext), is(true)); + } + class AutogenerateableId { @Id diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java index fd468fda5..95c0816f5 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorIntegrationTests.java @@ -54,13 +54,13 @@ public class MongoPersistentEntityIndexCreatorIntegrationTests { } @Test - public void foo() { + public void createsIndexForConfiguredMappingContextOnly() { List indexInfo = templateOne.indexOps(SampleEntity.class).getIndexInfo(); assertThat(indexInfo, hasSize(greaterThan(0))); assertThat(indexInfo, Matchers. hasItem(hasProperty("name", is("prop")))); - indexInfo = templateTwo.indexOps(SampleEntity.class).getIndexInfo(); + indexInfo = templateTwo.indexOps("sampleEntity").getIndexInfo(); assertThat(indexInfo, hasSize(0)); } } 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 index f47eddd44..10c7dc72b 100644 --- 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 @@ -81,6 +81,20 @@ public class MongoPersistentEntityIndexCreatorUnitTests { assertThat(creator.indexDefinition, is(nullValue())); } + /** + * @see DATAMONGO-530 + */ + @Test + public void isIndexCreatorForMappingContextHandedIntoConstructor() { + + MongoMappingContext mappingContext = new MongoMappingContext(); + mappingContext.initialize(); + + MongoPersistentEntityIndexCreator creator = new DummyMongoPersistentEntityIndexCreator(mappingContext, factory); + assertThat(creator.isIndexCreatorFor(mappingContext), is(true)); + assertThat(creator.isIndexCreatorFor(new MongoMappingContext()), is(false)); + } + static class Person { @Indexed(name = "indexName")