DATADOC-78: Refactored some of the code to use a new MappingContextAware interface available in spring-data-commons-core for obtaining a reference to the active MappingContext. Also added proper configuration to the namespace handler. Also tweaked the docs slightly.

This commit is contained in:
Jon Brisbin
2011-04-05 15:12:49 -05:00
committed by J. Brisbin
parent 6e1af80b5f
commit 3e2a60c89a
6 changed files with 871 additions and 883 deletions

View File

@@ -1,170 +1,191 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-document-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb</artifactId>
<packaging>jar</packaging>
<name>Spring Data MongoDB Support</name>
<properties>
<mongo.version>2.4</mongo.version>
</properties>
<dependencies>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-document-parent/pom.xml</relativePath>
</parent>
<artifactId>spring-data-mongodb</artifactId>
<packaging>jar</packaging>
<name>Spring Data MongoDB Support</name>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<properties>
<mongo.version>2.4</mongo.version>
</properties>
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<version>${data.commons.version}</version>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>${mongo.version}</version>
<exclusions>
<exclusion>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-mongodb</artifactId>
<version>2.1.1</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>com.google.code.morphia</groupId>
<artifactId>morphia</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-document-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<version>${data.commons.version}</version>
</dependency>
<!--
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
-->
<!-- Test dependencies -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>${mongo.version}</version>
<exclusions>
<exclusion>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-mongodb</artifactId>
<version>2.1.1</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>com.google.code.morphia</groupId>
<artifactId>morphia</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-test-sources</phase>
<goals>
<goal>test-process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/test-annotations</outputDirectory>
<processor>org.springframework.data.document.mongodb.repository.MongoAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>querydsl</id>
<name>Mysema QueryDsl</name>
<url>http://source.mysema.com/maven2/releases</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>2.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<optional>true</optional>
</dependency>
<!--
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
-->
<!-- Test dependencies -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-test-sources</phase>
<goals>
<goal>test-process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/test-annotations</outputDirectory>
<processor>org.springframework.data.document.mongodb.repository.MongoAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>querydsl</id>
<name>Mysema QueryDsl</name>
<url>http://source.mysema.com/maven2/releases</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@@ -57,7 +57,6 @@ import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
import org.springframework.data.document.mongodb.convert.MongoConverter;
import org.springframework.data.document.mongodb.convert.SimpleMongoConverter;
import org.springframework.data.document.mongodb.index.IndexDefinition;
import org.springframework.data.document.mongodb.mapping.Document;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
import org.springframework.data.document.mongodb.mapping.event.AfterConvertEvent;
import org.springframework.data.document.mongodb.mapping.event.AfterLoadEvent;
@@ -67,7 +66,9 @@ import org.springframework.data.document.mongodb.mapping.event.BeforeSaveEvent;
import org.springframework.data.document.mongodb.mapping.event.MongoMappingEvent;
import org.springframework.data.document.mongodb.query.Query;
import org.springframework.data.document.mongodb.query.Update;
import org.springframework.data.mapping.context.MappingContextAware;
import org.springframework.data.mapping.model.MappingContext;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.jca.cci.core.ConnectionCallback;
import org.springframework.util.Assert;
@@ -79,7 +80,7 @@ import org.springframework.util.Assert;
* @author Mark Pollack
* @author Oliver Gierke
*/
public class MongoTemplate implements InitializingBean, MongoOperations, ApplicationContextAware, ApplicationEventPublisherAware {
public class MongoTemplate implements InitializingBean, MongoOperations, ApplicationContextAware, ApplicationEventPublisherAware, MappingContextAware {
private static final Log LOGGER = LogFactory.getLog(MongoTemplate.class);
@@ -98,6 +99,7 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
private WriteResultChecking writeResultChecking = WriteResultChecking.NONE;
private MongoConverter mongoConverter;
private MappingContext mappingContext;
private final Mongo mongo;
private final MongoExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
@@ -202,6 +204,10 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
this.eventPublisher = applicationEventPublisher;
}
public void setMappingContext(MappingContext mappingContext) {
this.mappingContext = mappingContext;
}
/**
* Sets the username to use to connect to the Mongo database
*
@@ -508,19 +514,11 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
// Find methods that take a Query to express the query and that return a List of objects.
public <T> List<T> find(Query query, Class<T> targetClass) {
String collName = getEntityCollection(targetClass);
if (null == collName) {
collName = getRequiredDefaultCollectionName();
}
return find(collName, query, targetClass);
return find(getEntityCollection(targetClass), query, targetClass);
}
public <T> List<T> find(Query query, Class<T> targetClass, MongoReader<T> reader) {
String collName = getEntityCollection(targetClass);
if (null == collName) {
collName = getRequiredDefaultCollectionName();
}
return find(collName, query, targetClass, reader);
return find(getEntityCollection(targetClass), query, targetClass, reader);
}
public <T> List<T> find(String collectionName, final Query query, Class<T> targetClass) {
@@ -585,11 +583,7 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
* @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.Object)
*/
public void insert(Object objectToSave) {
String collName = getEntityCollection(objectToSave);
if (null == collName) {
collName = getRequiredDefaultCollectionName();
}
insert(collName, objectToSave);
insert(getEntityCollection(objectToSave), objectToSave);
}
/* (non-Javadoc)
@@ -603,11 +597,7 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
* @see org.springframework.data.document.mongodb.MongoOperations#insert(T, org.springframework.data.document.mongodb.MongoWriter)
*/
public <T> void insert(T objectToSave, MongoWriter<T> writer) {
String collName = getEntityCollection(objectToSave);
if (null == collName) {
collName = getDefaultCollectionName();
}
insert(collName, objectToSave, writer);
insert(getEntityCollection(objectToSave), objectToSave, writer);
}
/* (non-Javadoc)
@@ -1103,7 +1093,7 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
return name;
}
private String getEntityCollection(Object obj) {
private <T> String getEntityCollection(T obj) {
if (null != obj) {
return getEntityCollection(obj.getClass());
}
@@ -1111,26 +1101,15 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica
return null;
}
private String getEntityCollection(Class<?> clazz) {
if (mongoConverter instanceof MappingMongoConverter) {
MappingContext ctx = ((MappingMongoConverter) mongoConverter).getMappingContext();
MongoPersistentEntity entity = (MongoPersistentEntity) ctx.getPersistentEntity(clazz);
if (null != entity) {
return entity.getCollection();
private <T> String getEntityCollection(Class<T> clazz) {
if (null != mappingContext) {
PersistentEntity<T> entity = mappingContext.getPersistentEntity(clazz);
if (null != entity && entity instanceof MongoPersistentEntity) {
return ((MongoPersistentEntity) entity).getCollection();
}
}
// Entity hasn't yet been added, try and figure it out anyway
if (clazz.isAnnotationPresent(Document.class)) {
Document doc = clazz.getAnnotation(Document.class);
if (!"".equals(doc.collection())) {
return doc.collection();
}
// Default to simple name
return clazz.getSimpleName().toLowerCase();
}
return null;
// Otherwise, return the default for this template.
return getRequiredDefaultCollectionName();
}
/**

View File

@@ -33,8 +33,9 @@ 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.document.mongodb.mapping.MongoPersistentEntityIndexCreator;
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntityIndexCreator;
import org.springframework.data.mapping.context.MappingContextAwareBeanPostProcessor;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -44,77 +45,83 @@ import org.w3c.dom.Element;
*/
public class MongoMappingConverterParser extends AbstractBeanDefinitionParser {
static final String MAPPING_CONTEXT = "mappingContext";
private static final String INDEX_HELPER = "indexCreationHelper";
private static final String TEMPLATE = "mongoTemplate";
private static final String BASE_PACKAGE = "base-package";
static final String MAPPING_CONTEXT = "mappingContext";
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : "mappingConverter";
}
private static final String INDEX_HELPER = "indexCreationHelper";
private static final String TEMPLATE = "mongoTemplate";
private static final String POST_PROCESSOR = "mappingContextAwareBeanPostProcessor";
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
private static final String BASE_PACKAGE = "base-package";
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
registry.registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : "mappingConverter";
}
BeanDefinitionBuilder converterBuilder = BeanDefinitionBuilder.genericBeanDefinition(MappingMongoConverter.class);
converterBuilder.addPropertyReference("mappingContext", ctxRef);
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
String autowire = element.getAttribute("autowire");
if (StringUtils.hasText(autowire)) {
converterBuilder.addPropertyValue("autowirePersistentBeans", Boolean.parseBoolean(autowire));
}
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoMappingContext.class);
// Need a reference to a Mongo instance
String mongoRef = element.getAttribute("mongo-ref");
converterBuilder.addPropertyReference("mongo", StringUtils.hasText(mongoRef) ? mongoRef : "mongo");
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
try {
registry.getBeanDefinition(INDEX_HELPER);
} catch (NoSuchBeanDefinitionException ignored) {
String templateRef = element.getAttribute("mongo-template-ref");
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(ctxRef));
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(StringUtils.hasText(templateRef) ? templateRef : TEMPLATE));
registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition());
}
registry.registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
}
return converterBuilder.getBeanDefinition();
}
public Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {
String basePackage = element.getAttribute(BASE_PACKAGE);
if (!StringUtils.hasText(basePackage)) {
return null;
}
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
Set<String> classes = new ManagedSet<String>();
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
classes.add(candidate.getBeanClassName());
}
return classes;
}
try {
registry.getBeanDefinition(POST_PROCESSOR);
} catch (NoSuchBeanDefinitionException ignored) {
BeanDefinitionBuilder postProcBuilder = BeanDefinitionBuilder.genericBeanDefinition(MappingContextAwareBeanPostProcessor.class);
postProcBuilder.addPropertyValue("mappingContextBeanName", ctxRef);
registry.registerBeanDefinition(POST_PROCESSOR, postProcBuilder.getBeanDefinition());
}
BeanDefinitionBuilder converterBuilder = BeanDefinitionBuilder.genericBeanDefinition(MappingMongoConverter.class);
converterBuilder.addPropertyReference("mappingContext", ctxRef);
// Need a reference to a Mongo instance
String mongoRef = element.getAttribute("mongo-ref");
converterBuilder.addPropertyReference("mongo", StringUtils.hasText(mongoRef) ? mongoRef : "mongo");
try {
registry.getBeanDefinition(INDEX_HELPER);
} catch (NoSuchBeanDefinitionException ignored) {
String templateRef = element.getAttribute("mongo-template-ref");
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(ctxRef));
indexHelperBuilder.addConstructorArgValue(new RuntimeBeanReference(StringUtils.hasText(templateRef) ? templateRef : TEMPLATE));
registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition());
}
return converterBuilder.getBeanDefinition();
}
public Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {
String basePackage = element.getAttribute(BASE_PACKAGE);
if (!StringUtils.hasText(basePackage)) {
return null;
}
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
Set<String> classes = new ManagedSet<String>();
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
classes.add(candidate.getBeanClassName());
}
return classes;
}
}

View File

@@ -56,6 +56,9 @@ public class MongoPersistentEntity<T> extends BasicPersistentEntity<T> {
* @return
*/
public String getCollection() {
if (null == collection) {
this.collection = type.getSimpleName().toLowerCase();
}
return collection;
}

View File

@@ -23,8 +23,6 @@
http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<beans>
<!-- Default bean name is 'mongo' -->
<mongo:mongo host="localhost" port="27017"/>