diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java index 266f1ac23..3672575bb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java @@ -57,6 +57,7 @@ import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; import org.springframework.data.document.mongodb.event.CollectionCreatedEvent; import org.springframework.data.document.mongodb.event.InsertEvent; import org.springframework.data.document.mongodb.event.SaveEvent; +import org.springframework.data.document.mongodb.mapping.MongoMappingConfigurationBuilder; import org.springframework.data.document.mongodb.query.IndexDefinition; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.document.mongodb.query.Update; @@ -175,7 +176,6 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica Assert.notNull(mongo); Assert.notNull(databaseName); - this.mongoConverter = mongoConverter == null ? new SimpleMongoConverter() : mongoConverter; this.defaultCollectionName = defaultCollectionName; this.mongo = mongo; this.databaseName = databaseName; @@ -183,6 +183,7 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica if (writeResultChecking != null) { this.writeResultChecking = writeResultChecking; } + setMongoConverter(mongoConverter == null ? new SimpleMongoConverter() : mongoConverter); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { @@ -236,6 +237,10 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica return this.mongoConverter; } + public void setConverter(MongoConverter converter) { + this.mongoConverter = converter; + } + /* (non-Javadoc) * @see org.springframework.data.document.mongodb.MongoOperations#getDefaultCollectionName() */ @@ -1054,20 +1059,23 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica return resolved == null ? ex : resolved; } + private void initializeMappingMongoConverter(MappingMongoConverter converter) { + converter.setMongo(mongo); + converter.setDefaultDatabase(databaseName); + ((MongoMappingConfigurationBuilder) converter.getMappingContext().getMappingConfigurationBuilder()) + .setMongoTemplate(this); + } + /* - * (non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ + * (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ public void afterPropertiesSet() { if (this.getDefaultCollectionName() != null) { if (!collectionExists(getDefaultCollectionName())) { createCollection(getDefaultCollectionName(), null); } } - if (null != mongoConverter && mongoConverter instanceof MappingMongoConverter) { - ((MappingMongoConverter) mongoConverter).setMongo(mongo); - ((MappingMongoConverter) mongoConverter).setDefaultDatabase(databaseName); - } if (null != applicationContext) { eventPublishers.submit(new Runnable() { public void run() { @@ -1178,6 +1186,9 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica public void setMongoConverter(MongoConverter converter) { this.mongoConverter = converter; + if (null != converter && converter instanceof MappingMongoConverter) { + initializeMappingMongoConverter((MappingMongoConverter) mongoConverter); + } } public void setWriteResultChecking(WriteResultChecking resultChecking) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java index 19c88c1f0..35863a8ef 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoMappingConverterParser.java @@ -16,12 +16,21 @@ package org.springframework.data.document.mongodb.config; +import java.util.HashSet; +import java.util.Set; + import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.StringUtils; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.data.annotation.Persistent; +import org.springframework.data.document.mongodb.convert.MappingMongoConverter; +import org.springframework.data.document.mongodb.mapping.Document; +import org.springframework.data.mapping.model.MappingException; import org.w3c.dom.Element; /** @@ -37,17 +46,48 @@ public class MongoMappingConverterParser extends AbstractSingleBeanDefinitionPar @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { - String id = super.resolveId(element, definition, parserContext); - if (!StringUtils.hasText(id)) { - return "mongoMappingConverter"; - } - return id; + return "mappingConverter"; + } + + @Override + protected Class getBeanClass(Element element) { + return MappingMongoConverter.class; } @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - super.doParse(element, parserContext, builder); + String autowire = element.getAttribute("autowire"); + if (null != autowire || !"".equals(autowire)) { + builder.addPropertyValue("autowirePersistentBeans", Boolean.parseBoolean(autowire)); + } + // Need a reference to a MongoTemplate + String mongoRef = element.getAttribute("mongo-ref"); + if (null == mongoRef || "".equals(mongoRef)) { + mongoRef = "mongo"; + } + builder.addPropertyReference("mongo", mongoRef); + + // Scan for @Document entities + String basePackage = element.getAttribute(BASE_PACKAGE); + if (null != basePackage) { + ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(Document.class)); + scanner.addIncludeFilter(new AnnotationTypeFilter(Persistent.class)); + Set entities = scanner.findCandidateComponents(basePackage); + if (null != entities) { + Set> initialEntitySet = new HashSet>(entities.size()); + for (BeanDefinition def : entities) { + String clazzName = def.getBeanClassName(); + try { + initialEntitySet.add(Class.forName(clazzName)); + } catch (ClassNotFoundException e) { + throw new MappingException(e.getMessage(), e); + } + } + builder.addPropertyValue("initialEntitySet", initialEntitySet); + } + } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java index 29f8fa93e..120c1940a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoRepositoryNamespaceHandler.java @@ -33,9 +33,8 @@ public class MongoRepositoryNamespaceHandler extends NamespaceHandlerSupport { */ public void init() { - registerBeanDefinitionParser("repositories", - new MongoRepositoryConfigDefinitionParser()); - + registerBeanDefinitionParser("repositories", new MongoRepositoryConfigDefinitionParser()); + registerBeanDefinitionParser("mapping-converter", new MongoMappingConverterParser()); registerBeanDefinitionParser("mongo", new MongoParser()); registerBeanDefinitionParser("jmx", new MongoJmxParser()); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java index 000531d95..6e86d15b9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java @@ -24,9 +24,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; @@ -48,7 +50,9 @@ import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.ConversionServiceFactory; import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.data.document.mongodb.mapping.MongoMappingConfigurationBuilder; import org.springframework.data.mapping.AssociationHandler; +import org.springframework.data.mapping.BasicMappingContext; import org.springframework.data.mapping.MappingBeanHelper; import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.model.Association; @@ -68,7 +72,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; * @author Jon Brisbin * @author Oliver Gierke */ -public class MappingMongoConverter implements MongoConverter, ApplicationContextAware { +public class MappingMongoConverter implements MongoConverter, ApplicationContextAware, InitializingBean { private static final String CUSTOM_TYPE_KEY = "_class"; @SuppressWarnings({"unchecked"}) @@ -78,12 +82,13 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext protected final GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); protected final Map, Class> customTypeMapping = new HashMap, Class>(); protected SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); - protected MappingContext mappingContext; + protected MappingContext mappingContext = new BasicMappingContext(new MongoMappingConfigurationBuilder()); protected ApplicationContext applicationContext; protected boolean autowirePersistentBeans = false; protected boolean useFieldAccessOnly = true; protected Mongo mongo; protected String defaultDatabase; + protected Set> initialEntitySet = new HashSet>(); public MappingMongoConverter() { initializeConverters(); @@ -124,6 +129,11 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext public void setMappingContext(MappingContext mappingContext) { this.mappingContext = mappingContext; + if (initialEntitySet.size() > 0 && null == mappingContext.getPersistentEntity(initialEntitySet.iterator().next())) { + for (Class entity : initialEntitySet) { + mappingContext.addPersistentEntity(entity); + } + } } public Mongo getMongo() { @@ -158,6 +168,14 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext this.useFieldAccessOnly = useFieldAccessOnly; } + public Set> getInitialEntitySet() { + return initialEntitySet; + } + + public void setInitialEntitySet(Set> initialEntitySet) { + this.initialEntitySet = initialEntitySet; + } + public T convertObjectId(ObjectId id, Class targetType) { return conversionService.convert(id, targetType); } @@ -600,7 +618,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext * @param dbObject * @return */ - private Class findTypeToBeUsed(DBObject dbObject) { + protected Class findTypeToBeUsed(DBObject dbObject) { Object classToBeUsed = dbObject.get(CUSTOM_TYPE_KEY); try { @@ -610,6 +628,12 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } + public void afterPropertiesSet() throws Exception { + for (Class entity : initialEntitySet) { + //mappingContext.addPersistentEntity(entity); + } + } + /** * Simple singleton to convert {@link ObjectId}s to their {@link String} representation. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java index 0345526be..5f956e21c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingConfigurationBuilder.java @@ -38,7 +38,11 @@ import org.springframework.data.document.mongodb.index.IndexDirection; import org.springframework.data.document.mongodb.index.Indexed; import org.springframework.data.mapping.BasicMappingConfigurationBuilder; import org.springframework.data.mapping.MappingBeanHelper; -import org.springframework.data.mapping.model.*; +import org.springframework.data.mapping.model.Association; +import org.springframework.data.mapping.model.MappingConfigurationException; +import org.springframework.data.mapping.model.MappingContext; +import org.springframework.data.mapping.model.PersistentEntity; +import org.springframework.data.mapping.model.PersistentProperty; import org.springframework.data.util.TypeInformation; /** @@ -50,8 +54,15 @@ public class MongoMappingConfigurationBuilder extends BasicMappingConfigurationB protected Map fieldIndexes = new HashMap(); protected MongoTemplate mongoTemplate; + public MongoMappingConfigurationBuilder() { + } + public MongoMappingConfigurationBuilder(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; + augmentSimpleTypes(); + } + + protected void augmentSimpleTypes() { // Augment simpleTypes with MongoDB-specific classes Set> simpleTypes = MappingBeanHelper.getSimpleTypes(); simpleTypes.add(com.mongodb.DBRef.class); @@ -59,6 +70,14 @@ public class MongoMappingConfigurationBuilder extends BasicMappingConfigurationB simpleTypes.add(CodeWScope.class); } + public MongoTemplate getMongoTemplate() { + return mongoTemplate; + } + + public void setMongoTemplate(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + @Override public PersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, TypeInformation information) throws MappingConfigurationException { PersistentProperty property = new MongoPersistentProperty(field, descriptor, information); @@ -130,26 +149,30 @@ public class MongoMappingConfigurationBuilder extends BasicMappingConfigurationB final boolean unique, final boolean dropDups, final boolean sparse) { - mongoTemplate.execute(collection, new CollectionCallback() { - public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { - DBObject defObj; - if (null != def) { - defObj = (DBObject) JSON.parse(def); - } else { - defObj = new BasicDBObject(); - defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1)); + if (null != mongoTemplate) { + mongoTemplate.execute(collection, new CollectionCallback() { + public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { + DBObject defObj; + if (null != def) { + defObj = (DBObject) JSON.parse(def); + } else { + defObj = new BasicDBObject(); + defObj.put(name, (direction == IndexDirection.ASCENDING ? 1 : -1)); + } + DBObject opts = new BasicDBObject(); + if (!"".equals(name)) { + opts.put("name", name); + } + opts.put("dropDups", dropDups); + opts.put("sparse", sparse); + opts.put("unique", unique); + collection.ensureIndex(defObj, opts); + return null; } - DBObject opts = new BasicDBObject(); - if (!"".equals(name)) { - opts.put("name", name); - } - opts.put("dropDups", dropDups); - opts.put("sparse", sparse); - opts.put("unique", unique); - collection.ensureIndex(defObj, opts); - return null; - } - }); + }); + } else { + log.error("MongoTemplate was NULL! Not creating index: " + def + " on collection: " + collection); + } } } diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd index 3d800385d..e46cbdef6 100644 --- a/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd @@ -93,6 +93,43 @@ The host to connect to a MongoDB server. Default is localhost + + + + + + + + + + + + + + + + + + + + + + + + The reference to a Mongo. Will default to 'mongo'. + + + + + + { @DBRef private List accounts; private T address; - @Autowired - private MongoTemplate mongoTemplate; @PersistenceConstructor public Person(Integer ssn, String firstName, String lastName, Integer age, T address) { diff --git a/spring-data-mongodb/src/test/resources/mapping.xml b/spring-data-mongodb/src/test/resources/mapping.xml index 65ee2cfed..5f51d3f29 100644 --- a/spring-data-mongodb/src/test/resources/mapping.xml +++ b/spring-data-mongodb/src/test/resources/mapping.xml @@ -1,34 +1,23 @@ + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> - - - - - - - - - - - - - - - - - + + - + +