DATAMONGO-843 - Improvements in auditing configuration.

Repositories now declare a fallback MappingContext in case none is configured explicitly to make sure @EnableMongoAuditing also works without an explicit MappingContext bean defined.

AuditingEntityListener is now referring to the IsNewAwareAuditingHandler via an intermediate ObjectFactory to prevent the downstream dependencies from being instantiated eagerly at listener init time.

This is to prevent circular initialization dependencies as Spring accesses ApplicationEventListener beans very early in the container lifecycle to check whether they might be interested in a certain even and just dropped immediately afterwards.

Changed BeanNames.MAPPING_CONTEXT constant to mongoMappingContext to let the XML configuration be consistent with AbstractMongoConfiguration.mongoMappingContext().
This commit is contained in:
Thomas Darimont
2014-03-04 15:45:41 +01:00
committed by Oliver Gierke
parent 2839e9491f
commit 9370c1ee01
15 changed files with 230 additions and 83 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 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.
@@ -24,13 +24,14 @@ package org.springframework.data.mongodb.config;
*/
public abstract class BeanNames {
static final String MAPPING_CONTEXT = "mappingContext";
static final String INDEX_HELPER = "indexCreationHelper";
static final String MONGO = "mongo";
static final String DB_FACTORY = "mongoDbFactory";
static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener";
static final String IS_NEW_STRATEGY_FACTORY = "isNewStrategyFactory";
public static final String MAPPING_CONTEXT_BEAN_NAME = "mongoMappingContext";
static final String INDEX_HELPER_BEAN_NAME = "indexCreationHelper";
static final String MONGO_BEAN_NAME = "mongo";
static final String DB_FACTORY_BEAN_NAME = "mongoDbFactory";
static final String VALIDATING_EVENT_LISTENER_BEAN_NAME = "validatingMongoEventListener";
static final String IS_NEW_STRATEGY_FACTORY_BEAN_NAME = "isNewStrategyFactory";
static final String DEFAULT_CONVERTER_BEAN_NAME = "mappingConverter";
static final String MONGO_TEMPLATE = "mongoTemplate";
static final String GRID_FS_TEMPLATE = "gridFsTemplate";
static final String MONGO_TEMPLATE_BEAN_NAME = "mongoTemplate";
static final String GRID_FS_TEMPLATE_BEAN_NAME = "gridFsTemplate";
}

View File

@@ -43,7 +43,7 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : BeanNames.GRID_FS_TEMPLATE;
return StringUtils.hasText(id) ? id : BeanNames.GRID_FS_TEMPLATE_BEAN_NAME;
}
/*
@@ -64,7 +64,7 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
if (StringUtils.hasText(dbFactoryRef)) {
gridFsTemplateBuilder.addConstructorArgReference(dbFactoryRef);
} else {
gridFsTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY);
gridFsTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY_BEAN_NAME);
}
if (StringUtils.hasText(converterRef)) {
@@ -77,7 +77,7 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
gridFsTemplateBuilder.addConstructorArgValue(bucket);
}
return (AbstractBeanDefinition) helper.getComponentIdButFallback(gridFsTemplateBuilder, BeanNames.GRID_FS_TEMPLATE)
return (AbstractBeanDefinition) helper.getComponentIdButFallback(gridFsTemplateBuilder, BeanNames.GRID_FS_TEMPLATE_BEAN_NAME)
.getBeanDefinition();
}
}

View File

@@ -86,7 +86,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
BeanDefinitionRegistry registry = parserContext.getRegistry();
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
id = StringUtils.hasText(id) ? id : "mappingConverter";
id = StringUtils.hasText(id) ? id : DEFAULT_CONVERTER_BEAN_NAME;
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mapping Mongo Converter", element));
@@ -98,7 +98,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
// Need a reference to a Mongo instance
String dbFactoryRef = element.getAttribute("db-factory-ref");
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY;
dbFactoryRef = DB_FACTORY_BEAN_NAME;
}
// Converter
@@ -116,10 +116,10 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
}
try {
registry.getBeanDefinition(INDEX_HELPER);
registry.getBeanDefinition(INDEX_HELPER_BEAN_NAME);
} catch (NoSuchBeanDefinitionException ignored) {
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY;
dbFactoryRef = DB_FACTORY_BEAN_NAME;
}
BeanDefinitionBuilder indexHelperBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoPersistentEntityIndexCreator.class);
@@ -128,14 +128,14 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
indexHelperBuilder.addDependsOn(ctxRef);
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
INDEX_HELPER));
INDEX_HELPER_BEAN_NAME));
}
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
if (validatingMongoEventListener != null) {
parserContext.registerBeanComponent(new BeanComponentDefinition(validatingMongoEventListener,
VALIDATING_EVENT_LISTENER));
VALIDATING_EVENT_LISTENER_BEAN_NAME));
}
parserContext.registerBeanComponent(new BeanComponentDefinition(converterBuilder.getBeanDefinition(), id));
@@ -180,7 +180,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
return new RuntimeBeanReference(validatorName);
}
static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
public static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
BeanDefinition conversionsDefinition, String converterId) {
String ctxRef = element.getAttribute("mapping-context-ref");
@@ -215,7 +215,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
CamelCaseAbbreviatingFieldNamingStrategy.class));
}
ctxRef = converterId + "." + MAPPING_CONTEXT;
ctxRef = converterId == null || DEFAULT_CONVERTER_BEAN_NAME.equals(converterId) ? MAPPING_CONTEXT_BEAN_NAME
: converterId + "." + MAPPING_CONTEXT_BEAN_NAME;
parserContext.registerBeanComponent(componentDefinitionBuilder.getComponent(mappingContextBuilder, ctxRef));
return ctxRef;
@@ -310,9 +311,10 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY));
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder,
IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
return IS_NEW_STRATEGY_FACTORY;
return IS_NEW_STRATEGY_FACTORY_BEAN_NAME;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2014 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.
@@ -15,7 +15,10 @@
*/
package org.springframework.data.mongodb.config;
import org.springframework.beans.factory.config.BeanDefinition;
import static org.springframework.data.config.ParsingUtils.*;
import static org.springframework.data.mongodb.config.BeanNames.*;
import static org.springframework.data.mongodb.config.MappingMongoConverterParser.*;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
@@ -60,21 +63,23 @@ public class MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinit
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!registry.containsBeanDefinition(BeanNames.IS_NEW_STRATEGY_FACTORY)) {
String isNewStrategyFactoryName = IS_NEW_STRATEGY_FACTORY_BEAN_NAME;
String mappingContextName = MAPPING_CONTEXT_BEAN_NAME;
String mappingContextName = BeanNames.MAPPING_CONTEXT;
if (!registry.containsBeanDefinition(isNewStrategyFactoryName)) {
if (!registry.containsBeanDefinition(BeanNames.MAPPING_CONTEXT)) {
mappingContextName = MappingMongoConverterParser.potentiallyCreateMappingContext(element, parserContext, null,
BeanNames.DEFAULT_CONVERTER_BEAN_NAME);
if (!registry.containsBeanDefinition(mappingContextName)) {
mappingContextName = potentiallyCreateMappingContext(element, parserContext, null, null);
}
MappingMongoConverterParser.createIsNewStrategyFactoryBeanDefinition(mappingContextName, parserContext, element);
isNewStrategyFactoryName = createIsNewStrategyFactoryBeanDefinition(mappingContextName, parserContext, element);
}
BeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(BeanNames.IS_NEW_STRATEGY_FACTORY);
BeanDefinition handlerBeanDefinition = parser.parse(element, parserContext);
IsNewAwareAuditingHandlerBeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(
isNewStrategyFactoryName);
parser.parse(element, parserContext);
builder.addConstructorArgValue(handlerBeanDefinition);
builder.addConstructorArgValue(getObjectFactoryBeanDefinition(parser.getResolvedBeanName(),
parserContext.extractSource(element)));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2014 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.
@@ -18,13 +18,15 @@ package org.springframework.data.mongodb.config;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.auditing.config.AnnotationAuditingConfiguration;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
import org.springframework.data.support.IsNewStrategyFactory;
@@ -47,6 +49,15 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
return EnableMongoAuditing.class;
}
/*
* (non-Javadoc)
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName()
*/
@Override
protected String getAuditingHandlerBeanName() {
return "mongoAuditingHandler";
}
/*
* (non-Javadoc)
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
@@ -63,16 +74,16 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
/*
* (non-Javadoc)
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AnnotationAuditingConfiguration)
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AuditingConfiguration)
*/
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AnnotationAuditingConfiguration configuration) {
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
Assert.notNull(configuration, "AnnotationAuditingConfiguration must not be null!");
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
return configureDefaultAuditHandlerAttributes(configuration,
BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class)).addConstructorArgReference(
BeanNames.IS_NEW_STRATEGY_FACTORY);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
builder.addConstructorArgReference(BeanNames.IS_NEW_STRATEGY_FACTORY_BEAN_NAME);
return configureDefaultAuditHandlerAttributes(configuration, builder);
}
/*
@@ -86,8 +97,15 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
registerInfrastructureBeanWithId(BeanDefinitionBuilder.rootBeanDefinition(AuditingEventListener.class)
.addConstructorArgValue(auditingHandlerDefinition).getRawBeanDefinition(),
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ObjectFactoryCreatingFactoryBean.class);
builder.addPropertyValue("targetBeanName", getAuditingHandlerBeanName());
builder.setRole(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(AuditingEventListener.class);
listenerBeanDefinitionBuilder.addConstructorArgValue(builder.getBeanDefinition());
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
AuditingEventListener.class.getName(), registry);
}
@@ -96,10 +114,10 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
*/
private void registerIsNewStrategyFactoryIfNecessary(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(BeanNames.IS_NEW_STRATEGY_FACTORY)) {
registry.registerBeanDefinition(BeanNames.IS_NEW_STRATEGY_FACTORY,
if (!registry.containsBeanDefinition(BeanNames.IS_NEW_STRATEGY_FACTORY_BEAN_NAME)) {
registry.registerBeanDefinition(BeanNames.IS_NEW_STRATEGY_FACTORY_BEAN_NAME,
BeanDefinitionBuilder.rootBeanDefinition(MappingContextIsNewStrategyFactory.class)
.addConstructorArgReference(BeanNames.MAPPING_CONTEXT).getBeanDefinition());
.addConstructorArgReference(BeanNames.MAPPING_CONTEXT_BEAN_NAME).getBeanDefinition());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 by the original author(s).
* Copyright 2011-2014 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY;
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY_BEAN_NAME;
}
/*
@@ -103,7 +103,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
parserContext.registerBeanComponent(component);
return (AbstractBeanDefinition) helper.getComponentIdButFallback(dbFactoryBuilder, BeanNames.DB_FACTORY)
return (AbstractBeanDefinition) helper.getComponentIdButFallback(dbFactoryBuilder, BeanNames.DB_FACTORY_BEAN_NAME)
.getBeanDefinition();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2014 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.
@@ -58,7 +58,7 @@ public class MongoParser implements BeanDefinitionParser {
MongoParsingUtils.parseMongoOptions(element, builder);
MongoParsingUtils.parseReplicaSet(element, builder);
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO;
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 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.
@@ -35,6 +35,7 @@ import org.w3c.dom.Element;
* {@link BeanDefinitionParser} to parse {@code template} elements into {@link BeanDefinition}s.
*
* @author Martin Baumgartner
* @author Oliver Gierke
*/
class MongoTemplateParser extends AbstractBeanDefinitionParser {
@@ -47,7 +48,7 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : BeanNames.MONGO_TEMPLATE;
return StringUtils.hasText(id) ? id : BeanNames.MONGO_TEMPLATE_BEAN_NAME;
}
/*
@@ -68,7 +69,7 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
if (StringUtils.hasText(dbFactoryRef)) {
mongoTemplateBuilder.addConstructorArgReference(dbFactoryRef);
} else {
mongoTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY);
mongoTemplateBuilder.addConstructorArgReference(BeanNames.DB_FACTORY_BEAN_NAME);
}
if (StringUtils.hasText(converterRef)) {
@@ -80,7 +81,7 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
BeanComponentDefinition component = helper.getComponent(writeConcernPropertyEditorBuilder);
parserContext.registerBeanComponent(component);
return (AbstractBeanDefinition) helper.getComponentIdButFallback(mongoTemplateBuilder, BeanNames.MONGO_TEMPLATE)
.getBeanDefinition();
return (AbstractBeanDefinition) helper.getComponentIdButFallback(mongoTemplateBuilder,
BeanNames.MONGO_TEMPLATE_BEAN_NAME).getBeanDefinition();
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.core.mapping.event;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
@@ -25,20 +26,22 @@ import org.springframework.util.Assert;
* Event listener to populate auditing related fields on an entity about to be saved.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public class AuditingEventListener implements ApplicationListener<BeforeConvertEvent<Object>> {
private final IsNewAwareAuditingHandler auditingHandler;
private final ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory;
/**
* Creates a new {@link AuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}.
* Creates a new {@link AuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}
* provided by the given {@link ObjectFactory}.
*
* @param auditingHandler must not be {@literal null}.
* @param auditingHandlerFactory must not be {@literal null}.
*/
public AuditingEventListener(IsNewAwareAuditingHandler auditingHandler) {
public AuditingEventListener(ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory) {
Assert.notNull(auditingHandler, "IsNewAwareAuditingHandler must not be null!");
this.auditingHandler = auditingHandler;
Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!");
this.auditingHandlerFactory = auditingHandlerFactory;
}
/*
@@ -48,6 +51,6 @@ public class AuditingEventListener implements ApplicationListener<BeforeConvertE
public void onApplicationEvent(BeforeConvertEvent<Object> event) {
Object entity = event.getSource();
auditingHandler.markAudited(entity);
auditingHandlerFactory.getObject().markAudited(entity);
}
}

View File

@@ -15,13 +15,19 @@
*/
package org.springframework.data.mongodb.repository.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.mongodb.config.BeanNames;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.w3c.dom.Element;
@@ -35,6 +41,8 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
private static final String MONGO_TEMPLATE_REF = "mongo-template-ref";
private static final String CREATE_QUERY_INDEXES = "create-query-indexes";
private boolean fallbackMappingContextCreated = false;
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModulePrefix()
@@ -52,6 +60,18 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
return MongoRepositoryFactoryBean.class.getName();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.RepositoryConfigurationSource)
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource source) {
if (fallbackMappingContextCreated) {
builder.addPropertyReference("mappingContext", BeanNames.MAPPING_CONTEXT_BEAN_NAME);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource)
@@ -77,4 +97,21 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
builder.addPropertyReference("mongoOperations", attributes.getString("mongoTemplateRef"));
builder.addPropertyValue("createIndexesForQueryMethods", attributes.getBoolean("createIndexesForQueryMethods"));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource)
*/
@Override
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource configurationSource) {
if (!registry.containsBeanDefinition(BeanNames.MAPPING_CONTEXT_BEAN_NAME)) {
RootBeanDefinition definition = new RootBeanDefinition(MongoMappingContext.class);
definition.setRole(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);
definition.setSource(configurationSource.getSource());
registry.registerBeanDefinition(BeanNames.MAPPING_CONTEXT_BEAN_NAME, definition);
}
}
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.support;
import java.io.Serializable;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.Repository;
@@ -34,6 +35,7 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
private MongoOperations operations;
private boolean createIndexesForQueryMethods = false;
private boolean mappingContextConfigured = false;
/**
* Configures the {@link MongoOperations} to be used.
@@ -42,7 +44,6 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
*/
public void setMongoOperations(MongoOperations operations) {
this.operations = operations;
setMappingContext(operations.getConverter().getMappingContext());
}
/**
@@ -54,6 +55,17 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
this.createIndexesForQueryMethods = createIndexesForQueryMethods;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#setMappingContext(org.springframework.data.mapping.context.MappingContext)
*/
@Override
protected void setMappingContext(MappingContext<?, ?> mappingContext) {
super.setMappingContext(mappingContext);
this.mappingContextConfigured = true;
}
/*
* (non-Javadoc)
*
@@ -95,5 +107,9 @@ public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
super.afterPropertiesSet();
Assert.notNull(operations, "MongoTemplate must not be null!");
if (!mappingContextConfigured) {
setMappingContext(operations.getConverter().getMappingContext());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2014 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.
@@ -19,24 +19,26 @@ import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.net.UnknownHostException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.mongodb.core.AuditablePerson;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
/**
@@ -56,16 +58,16 @@ public class AuditingViaJavaConfigRepositoriesTests {
@Configuration
@EnableMongoAuditing(auditorAwareRef = "auditorProvider")
@EnableMongoRepositories(basePackageClasses = AuditablePersonRepository.class, considerNestedRepositories = true)
static class Config {
static class Config extends AbstractMongoConfiguration {
@Bean
public MongoOperations mongoTemplate() throws Exception {
return new MongoTemplate(new SimpleMongoDbFactory(new MongoClient(), "database"));
@Override
protected String getDatabaseName() {
return "database";
}
@Bean
public MongoMappingContext mappingContext() {
return new MongoMappingContext();
@Override
public Mongo mongo() throws Exception {
return new MongoClient();
}
@Bean
@@ -81,6 +83,9 @@ public class AuditingViaJavaConfigRepositoriesTests {
this.auditor = auditablePersonRepository.save(new AuditablePerson("auditor"));
}
/**
* @DATAMONGO-792
*/
@Test
public void basicAuditing() {
@@ -89,13 +94,32 @@ public class AuditingViaJavaConfigRepositoriesTests {
AuditablePerson user = new AuditablePerson("user");
AuditablePerson savedUser = auditablePersonRepository.save(user);
System.out.println(savedUser);
AuditablePerson createdBy = savedUser.getCreatedBy();
assertThat(createdBy, is(notNullValue()));
assertThat(createdBy.getFirstname(), is(this.auditor.getFirstname()));
}
/**
* @see DATAMONGO-843
*/
@Test
@SuppressWarnings("resource")
public void auditingUsesFallbackMappingContextIfNoneConfigured() {
new AnnotationConfigApplicationContext(SimpleConfig.class);
}
@Repository
static interface AuditablePersonRepository extends MongoRepository<AuditablePerson, String> {}
@Configuration
@EnableMongoRepositories
@EnableMongoAuditing
static class SimpleConfig {
@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
return new MongoTemplate(new SimpleMongoDbFactory(new MongoClient(), "database"));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 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.
@@ -57,6 +57,9 @@ public class MappingMongoConverterParserIntegrationTests {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter.xml"));
}
/**
* @see DATAMONGO-243
*/
@Test
public void allowsDbFactoryRefAttribute() {
@@ -64,6 +67,9 @@ public class MappingMongoConverterParserIntegrationTests {
factory.getBean("converter");
}
/**
* @see DATAMONGO-725
*/
@Test
public void hasCustomTypeMapper() {
@@ -73,6 +79,9 @@ public class MappingMongoConverterParserIntegrationTests {
assertThat(converter.getTypeMapper(), is(customMongoTypeMapper));
}
/**
* @see DATAMONGO-301
*/
@Test
public void scansForConverterAndSetsUpCustomConversionsAccordingly() {
@@ -87,7 +96,7 @@ public class MappingMongoConverterParserIntegrationTests {
@Test
public void activatesAbbreviatingPropertiesCorrectly() {
BeanDefinition definition = factory.getBeanDefinition("abbreviatingConverter.mappingContext");
BeanDefinition definition = factory.getBeanDefinition("abbreviatingConverter.mongoMappingContext");
Object value = definition.getPropertyValues().getPropertyValue("fieldNamingStrategy").getValue();
assertThat(value, is(instanceOf(BeanDefinition.class)));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2014 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.
@@ -34,6 +34,7 @@ import org.springframework.core.io.ClassPathResource;
* @see DATAMONGO-36
* @author Maciej Walkowiak
* @author Thomas Darimont
* @author Oliver Gierke
*/
public class MappingMongoConverterParserValidationIntegrationTests {
@@ -46,31 +47,43 @@ public class MappingMongoConverterParserValidationIntegrationTests {
reader = new XmlBeanDefinitionReader(factory);
}
/**
* @see DATAMONGO-36
*/
@Test
public void validatingEventListenerCreatedWithDefaultConfig() {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-default.xml"));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER), is(not(nullValue())));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER_BEAN_NAME), is(not(nullValue())));
}
/**
* @see DATAMONGO-36
*/
@Test
public void validatingEventListenerCreatedWhenValidationEnabled() {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-validation-enabled.xml"));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER), is(not(nullValue())));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER_BEAN_NAME), is(not(nullValue())));
}
/**
* @see DATAMONGO-36
*/
@Test(expected = NoSuchBeanDefinitionException.class)
public void validatingEventListenersIsNotCreatedWhenDisabled() {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-validation-disabled.xml"));
factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER);
factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER_BEAN_NAME);
}
/**
* @see DATAMONGO-36
*/
@Test
public void validatingEventListenerCreatedWithCustomTypeMapperConfig() {
reader.loadBeanDefinitions(new ClassPathResource("namespace/converter-custom-typeMapper.xml"));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER), is(not(nullValue())));
assertThat(factory.getBean(BeanNames.VALIDATING_EVENT_LISTENER_BEAN_NAME), is(not(nullValue())));
}
}

View File

@@ -23,6 +23,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.data.annotation.Id;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
@@ -33,6 +35,7 @@ import org.springframework.data.support.IsNewStrategyFactory;
* Unit tests for {@link AuditingEventListener}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@RunWith(MockitoJUnitRunner.class)
public class AuditingEventListenerUnitTests {
@@ -52,14 +55,26 @@ public class AuditingEventListenerUnitTests {
doNothing().when(handler).markCreated(Mockito.any(Object.class));
doNothing().when(handler).markModified(Mockito.any(Object.class));
listener = new AuditingEventListener(handler);
listener = new AuditingEventListener(new ObjectFactory<IsNewAwareAuditingHandler>() {
@Override
public IsNewAwareAuditingHandler getObject() throws BeansException {
return handler;
}
});
}
/**
* @see DATAMONGO-577
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullAuditingHandler() {
new AuditingEventListener(null);
}
/**
* @see DATAMONGO-577
*/
@Test
public void triggersCreationMarkForObjectWithEmptyId() {
@@ -70,6 +85,9 @@ public class AuditingEventListenerUnitTests {
verify(handler, times(0)).markModified(any(Sample.class));
}
/**
* @see DATAMONGO-577
*/
@Test
public void triggersModificationMarkForObjectWithSetId() {