Skip to content

Commit ad287ef

Browse files
committed
DATADOC-143 - Made MongoMappingContext the default converter for the template, which also meant:
Several changes to how objects are initialized inside the template: 1. In one is not specified, a MappingMongoConverter is created and set as the default. 2. A special ApplicationEventPublisher implementation is installed by default to handle creating indexes when the template isn't used inside a Spring application context. 3. If a Spring application context is available, it will be set as the template's application context and eventPublisher, with the index creator being registered as an event listener if one isn't already present. The tests had to be changed in a couple places to accurately reflect how mapping contexts and converters are now handled.
1 parent 98da8be commit ad287ef

17 files changed

+209
-230
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@
4040
import org.apache.commons.logging.Log;
4141
import org.apache.commons.logging.LogFactory;
4242
import org.bson.types.ObjectId;
43+
import org.springframework.beans.BeansException;
44+
import org.springframework.context.ApplicationContext;
45+
import org.springframework.context.ApplicationContextAware;
4346
import org.springframework.context.ApplicationEventPublisher;
4447
import org.springframework.context.ApplicationEventPublisherAware;
48+
import org.springframework.context.ConfigurableApplicationContext;
4549
import org.springframework.core.convert.ConversionFailedException;
4650
import org.springframework.dao.DataAccessException;
4751
import org.springframework.dao.DataIntegrityViolationException;
@@ -51,6 +55,7 @@
5155
import org.springframework.data.document.mongodb.index.IndexDefinition;
5256
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
5357
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
58+
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntityIndexCreator;
5459
import org.springframework.data.document.mongodb.mapping.MongoPersistentProperty;
5560
import org.springframework.data.document.mongodb.mapping.event.AfterConvertEvent;
5661
import org.springframework.data.document.mongodb.mapping.event.AfterLoadEvent;
@@ -76,7 +81,7 @@
7681
* @author Mark Pollack
7782
* @author Oliver Gierke
7883
*/
79-
public class MongoTemplate implements MongoOperations, ApplicationEventPublisherAware {
84+
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
8085

8186
private static final Log LOGGER = LogFactory.getLog(MongoTemplate.class);
8287

@@ -99,13 +104,15 @@ public class MongoTemplate implements MongoOperations, ApplicationEventPublisher
99104
*/
100105
private boolean slaveOk = false;
101106

102-
private final MongoConverter mongoConverter;
103-
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
104-
private final MongoDbFactory mongoDbFactory;
105-
private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
106-
private final QueryMapper mapper;
107+
private MongoConverter mongoConverter;
108+
private MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
109+
private MongoDbFactory mongoDbFactory;
110+
private MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
111+
private QueryMapper mapper;
107112

113+
private ApplicationContext applicationContext;
108114
private ApplicationEventPublisher eventPublisher;
115+
private MongoPersistentEntityIndexCreator indexCreator;
109116

110117
/**
111118
* Constructor used for a basic template configuration
@@ -114,7 +121,7 @@ public class MongoTemplate implements MongoOperations, ApplicationEventPublisher
114121
* @param databaseName
115122
*/
116123
public MongoTemplate(Mongo mongo, String databaseName) {
117-
this(new MongoDbFactoryBean(mongo, databaseName));
124+
this(new MongoDbFactoryBean(mongo, databaseName), null, null, null);
118125
}
119126

120127
/**
@@ -126,7 +133,7 @@ public MongoTemplate(Mongo mongo, String databaseName) {
126133
* @param mongoConverter
127134
*/
128135
public MongoTemplate(Mongo mongo, String databaseName, MongoConverter mongoConverter) {
129-
this(new MongoDbFactoryBean(mongo, databaseName), mongoConverter);
136+
this(new MongoDbFactoryBean(mongo, databaseName), mongoConverter, null, null);
130137
}
131138

132139
/**
@@ -135,7 +142,7 @@ public MongoTemplate(Mongo mongo, String databaseName, MongoConverter mongoConve
135142
* @param mongoDbFactory
136143
*/
137144
public MongoTemplate(MongoDbFactory mongoDbFactory) {
138-
this(mongoDbFactory, null);
145+
this(mongoDbFactory, null, null, null);
139146
}
140147

141148
/**
@@ -162,37 +169,52 @@ public MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverte
162169
WriteConcern writeConcern,
163170
WriteResultChecking writeResultChecking) {
164171
Assert.notNull(mongoDbFactory);
165-
172+
// Always need a MongoDbFactory for obtaining instances of DB
166173
this.mongoDbFactory = mongoDbFactory;
167-
this.mongoConverter = mongoConverter == null ? getDefaultMongoConverter() : mongoConverter;
168-
this.writeConcern = writeConcern;
169-
170-
if (this.mongoConverter instanceof MappingMongoConverter) {
171-
initializeMappingMongoConverter((MappingMongoConverter) this.mongoConverter);
174+
// Conversion of DBObject to POJO handled either custom or by default (MappingMongoConverter)
175+
if (null == mongoConverter) {
176+
this.mongoConverter = getDefaultMongoConverter();
177+
} else {
178+
this.mongoConverter = mongoConverter;
172179
}
173-
174-
this.mappingContext = this.mongoConverter.getMappingContext();
175-
this.mapper = new QueryMapper(this.mongoConverter);
176-
180+
// We always have a mapping context in the converter, whether it's a simple one or not
181+
mappingContext = this.mongoConverter.getMappingContext();
182+
// We create indexes based on mapping events
183+
if (null != mappingContext && mappingContext instanceof MongoMappingContext) {
184+
indexCreator = new MongoPersistentEntityIndexCreator((MongoMappingContext) mappingContext, mongoDbFactory);
185+
eventPublisher = new MongoMappingEventPublisher(indexCreator);
186+
if (mappingContext instanceof ApplicationEventPublisherAware) {
187+
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
188+
}
189+
}
190+
// WriteConcern
191+
this.writeConcern = writeConcern;
192+
// For converting ID names and values throughout Query objects
193+
mapper = new QueryMapper(this.mongoConverter);
194+
// Track WriteResults?
177195
if (writeResultChecking != null) {
178196
this.writeResultChecking = writeResultChecking;
179197
}
180198

181-
if (this.mappingContext instanceof MongoMappingContext) {
182-
this.eventPublisher = new MongoMappingEventPublisher((MongoMappingContext) mappingContext, mongoDbFactory);
183-
}
184-
185199
}
186200

187201
private final MongoConverter getDefaultMongoConverter() {
188202
//ToDo: maybe add some additional configurations to this very basic one
189-
MappingMongoConverter converter = new MappingMongoConverter(new MongoMappingContext());
203+
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory, new MongoMappingContext());
190204
converter.afterPropertiesSet();
191205
return converter;
192206
}
193207

194-
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
195-
this.eventPublisher = applicationEventPublisher;
208+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
209+
this.applicationContext = applicationContext;
210+
String[] beans = applicationContext.getBeanNamesForType(MongoPersistentEntityIndexCreator.class);
211+
if ((null == beans || beans.length == 0) && applicationContext instanceof ConfigurableApplicationContext) {
212+
((ConfigurableApplicationContext) applicationContext).addApplicationListener(indexCreator);
213+
}
214+
eventPublisher = applicationContext;
215+
if (mappingContext instanceof ApplicationEventPublisherAware) {
216+
((ApplicationEventPublisherAware) mappingContext).setApplicationEventPublisher(eventPublisher);
217+
}
196218
}
197219

198220
/**
@@ -213,9 +235,13 @@ public MongoDbFactory getDbFactory() {
213235
return this.mongoDbFactory;
214236
}
215237

238+
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext() {
239+
return mappingContext;
240+
}
241+
216242
/* (non-Javadoc)
217-
* @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName()
218-
*/
243+
* @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName()
244+
*/
219245
public String getCollectionName(Class<?> clazz) {
220246
return this.determineCollectionName(clazz);
221247
}
@@ -417,12 +443,12 @@ public DBCursor prepare(DBCursor cursor) {
417443
public <T> List<T> find(String collectionName, Query query, Class<T> targetClass, CursorPreparer preparer) {
418444
return doFind(collectionName, query.getQueryObject(), query.getFieldsObject(), targetClass, preparer);
419445
}
420-
446+
421447
public <T> T findById(Object id, Class<T> targetClass) {
422448
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(targetClass);
423449
return findById(persistentEntity.getCollection(), id, targetClass);
424450
}
425-
451+
426452
public <T> T findById(String collectionName, Object id, Class<T> targetClass) {
427453
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(targetClass);
428454
MongoPersistentProperty idProperty = persistentEntity.getIdProperty();
@@ -455,15 +481,15 @@ public void insert(Object objectToSave) {
455481
public void insert(String collectionName, Object objectToSave) {
456482
doInsert(collectionName, objectToSave, this.mongoConverter);
457483
}
458-
484+
459485
/**
460-
* Prepare the collection before any processing is done using it. This allows a convenient way to apply
486+
* Prepare the collection before any processing is done using it. This allows a convenient way to apply
461487
* settings like slaveOk() etc. Can be overridden in sub-classes.
462-
*
488+
*
463489
* @param collection
464490
*/
465491
protected void prepareCollection(DBCollection collection) {
466-
if(this.slaveOk) {
492+
if (this.slaveOk) {
467493
collection.slaveOk();
468494
}
469495
}
@@ -975,7 +1001,7 @@ protected Object getIdValue(Object object) {
9751001
throw new MappingException(e.getMessage(), e);
9761002
}
9771003
}
978-
1004+
9791005
protected String getIdPropertyName(Object object) {
9801006
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(object.getClass());
9811007
MongoPersistentProperty idProperty = persistentEntity.getIdProperty();
@@ -1027,18 +1053,15 @@ private DBCollection getAndPrepareCollection(DB db, String collectionName) {
10271053
* <li>Execute the given {@link ConnectionCallback} for a {@link DBObject}.</li>
10281054
* <li>Apply the given {@link DbObjectCallback} to each of the {@link DBObject}s to obtain the result.</li>
10291055
* <ol>
1030-
*
1056+
*
10311057
* @param <T>
1032-
* @param collectionCallback
1033-
* the callback to retrieve the {@link DBObject} with
1034-
* @param objectCallback
1035-
* the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1036-
* @param collectionName
1037-
* the collection to be queried
1058+
* @param collectionCallback the callback to retrieve the {@link DBObject} with
1059+
* @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1060+
* @param collectionName the collection to be queried
10381061
* @return
10391062
*/
10401063
private <T> T executeFindOneInternal(CollectionCallback<DBObject> collectionCallback, DbObjectCallback<T> objectCallback,
1041-
String collectionName) {
1064+
String collectionName) {
10421065

10431066
try {
10441067
T result = objectCallback.doWith(collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName)));
@@ -1058,20 +1081,16 @@ private <T> T executeFindOneInternal(CollectionCallback<DBObject> collectionCall
10581081
* <li>Iterate over the {@link DBCursor} and applies the given {@link DbObjectCallback} to each of the
10591082
* {@link DBObject}s collecting the actual result {@link List}.</li>
10601083
* <ol>
1061-
*
1084+
*
10621085
* @param <T>
1063-
* @param collectionCallback
1064-
* the callback to retrieve the {@link DBCursor} with
1065-
* @param preparer
1066-
* the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it
1067-
* @param objectCallback
1068-
* the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1069-
* @param collectionName
1070-
* the collection to be queried
1086+
* @param collectionCallback the callback to retrieve the {@link DBCursor} with
1087+
* @param preparer the {@link CursorPreparer} to potentially modify the {@link DBCursor} before ireating over it
1088+
* @param objectCallback the {@link DbObjectCallback} to transform {@link DBObject}s into the actual domain type
1089+
* @param collectionName the collection to be queried
10711090
* @return
10721091
*/
10731092
private <T> List<T> executeFindMultiInternal(CollectionCallback<DBCursor> collectionCallback, CursorPreparer preparer,
1074-
DbObjectCallback<T> objectCallback, String collectionName) {
1093+
DbObjectCallback<T> objectCallback, String collectionName) {
10751094

10761095
try {
10771096
DBCursor cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
@@ -1179,11 +1198,6 @@ private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex)
11791198
return resolved == null ? ex : resolved;
11801199
}
11811200

1182-
private void initializeMappingMongoConverter(MappingMongoConverter converter) {
1183-
converter.setMongo(this.mongoDbFactory.getMongo());
1184-
converter.setDefaultDatabase(this.mongoDbFactory.getDatabaseName());
1185-
}
1186-
11871201
/**
11881202
* Simple {@link CollectionCallback} that takes a query {@link DBObject} plus an optional fields specification
11891203
* {@link DBObject} and executes that against the {@link DBCollection}.

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/AbstractMongoConfiguration.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,34 @@
3131
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
3232
import org.springframework.data.document.mongodb.mapping.Document;
3333
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
34-
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntityIndexCreator;
3534
import org.springframework.data.mapping.context.MappingContextAwareBeanPostProcessor;
3635
import org.springframework.util.ClassUtils;
3736
import org.springframework.util.StringUtils;
3837

3938
@Configuration
4039
public abstract class AbstractMongoConfiguration {
4140

41+
public abstract String defaultDatabaseName();
42+
4243
@Bean
4344
public abstract Mongo mongo() throws Exception;
4445

4546
@Bean
4647
public abstract MongoTemplate mongoTemplate() throws Exception;
4748

48-
public String defaultDatabaseName() {
49-
return "db";
50-
}
51-
5249
@Bean
5350
public MongoDbFactory mongoDbFactory() throws Exception {
5451
return new MongoDbFactoryBean(mongo(), defaultDatabaseName());
5552
}
5653

57-
public String getMappingBasePackage() {
54+
public String mappingBasePackage() {
5855
return "";
5956
}
6057

6158
@Bean
6259
public MongoMappingContext mongoMappingContext() throws ClassNotFoundException, LinkageError {
6360
MongoMappingContext mappingContext = new MongoMappingContext();
64-
String basePackage = getMappingBasePackage();
61+
String basePackage = mappingBasePackage();
6562
if (StringUtils.hasText(basePackage)) {
6663
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
6764
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
@@ -78,8 +75,7 @@ public MongoMappingContext mongoMappingContext() throws ClassNotFoundException,
7875

7976
@Bean
8077
public MappingMongoConverter mappingMongoConverter() throws Exception {
81-
MappingMongoConverter converter = new MappingMongoConverter(mongoMappingContext());
82-
converter.setMongo(mongo());
78+
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), mongoMappingContext());
8379
afterMappingMongoConverterCreation(converter);
8480
return converter;
8581
}
@@ -99,8 +95,4 @@ public MappingContextAwareBeanPostProcessor mappingContextAwareBeanPostProcessor
9995
return bpp;
10096
}
10197

102-
@Bean MongoPersistentEntityIndexCreator mongoPersistentEntityIndexCreator() throws Exception {
103-
MongoPersistentEntityIndexCreator indexCreator = new MongoPersistentEntityIndexCreator(mongoMappingContext(), mongoDbFactory());
104-
return indexCreator;
105-
}
10698
}

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MappingMongoConverterParser.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,15 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
9292
converterBuilder.addConstructorArgReference(ctxRef);
9393

9494
// Need a reference to a Mongo instance
95-
String mongoRef = element.getAttribute("mongo-ref");
96-
if (!StringUtils.hasText(mongoRef)) {
97-
mongoRef = MONGO;
95+
String dbFactoryRef = element.getAttribute("db-factory-ref");
96+
if (!StringUtils.hasText(dbFactoryRef)) {
97+
dbFactoryRef = DB_FACTORY;
9898
}
99-
converterBuilder.addPropertyReference("mongo", mongoRef);
99+
converterBuilder.addPropertyReference("mongoDbFactory", dbFactoryRef);
100100

101101
try {
102102
registry.getBeanDefinition(INDEX_HELPER);
103103
} catch (NoSuchBeanDefinitionException ignored) {
104-
String dbFactoryRef = element.getAttribute("db-factory-ref");
105104
if (!StringUtils.hasText(dbFactoryRef)) {
106105
dbFactoryRef = DB_FACTORY;
107106
}

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoDbFactoryParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
8787
Element mongoEl = DomUtils.getChildElementByTagName(element, "mongo");
8888
if (null != mongoEl) {
8989
String overrideHost = mongoEl.getAttribute("host");
90-
mongoBuilder.addPropertyValue("host", (overrideHost != null ? overrideHost : host));
90+
mongoBuilder.addPropertyValue("host", (StringUtils.hasText(overrideHost) ? overrideHost : host));
9191
String overridePort = mongoEl.getAttribute("port");
92-
mongoBuilder.addPropertyValue("port", (overridePort != null ? overridePort : port));
92+
mongoBuilder.addPropertyValue("port", (StringUtils.hasText(overridePort) ? overridePort : port));
9393
new MongoParser().parseOptions(parserContext, mongoEl, mongoBuilder);
9494
}
9595
registry.registerBeanDefinition(MONGO, mongoBuilder.getBeanDefinition());

0 commit comments

Comments
 (0)