From 3c117db43b8b11faba5d892f77ead1dfab2901d9 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 28 Sep 2016 16:22:20 +0200 Subject: [PATCH] DATAMONGO-1498 - Removed defaulting of MongoMappingContext for repositories and auditing. Previously we created a default bean definition for MongoMappingContext if none was present in the application context. That lookup for an existing one unfortunately comes too early, especially with Spring Boot in place. This then caused the MappingContext not being aware of the custom conversions and simply types registered by Boot. We now removed the defaulting relying on a MappingMongoConverter being present in the Application context (which usually is the case for the usage with AbstractMongoConfiguration or the XML alternative. We use that bean to lookup the MappingContext. --- .../config/MongoAuditingRegistrar.java | 76 +++++++++++++------ ...MongoRepositoryConfigurationExtension.java | 45 +---------- ...uditingViaJavaConfigRepositoriesTests.java | 28 +++---- 3 files changed, 68 insertions(+), 81 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingRegistrar.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingRegistrar.java index 5e6497283..bff98808d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingRegistrar.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2016 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,24 +15,24 @@ */ package org.springframework.data.mongodb.config; -import static org.springframework.beans.factory.config.BeanDefinition.*; -import static org.springframework.data.mongodb.config.BeanNames.*; - import java.lang.annotation.Annotation; +import org.springframework.beans.factory.FactoryBean; 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.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.auditing.IsNewAwareAuditingHandler; import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport; import org.springframework.data.auditing.config.AuditingConfiguration; import org.springframework.data.config.ParsingUtils; -import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener; -import org.springframework.data.support.IsNewStrategyFactory; import org.springframework.util.Assert; /** @@ -71,7 +71,6 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!"); Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); - defaultDependenciesIfNecessary(registry, annotationMetadata); super.registerBeanDefinitions(annotationMetadata, registry); } @@ -85,7 +84,11 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { Assert.notNull(configuration, "AuditingConfiguration must not be null!"); BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class); - builder.addConstructorArgReference(MAPPING_CONTEXT_BEAN_NAME); + + BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(MongoMappingContextLookup.class); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR); + + builder.addConstructorArgValue(definition.getBeanDefinition()); return configureDefaultAuditHandlerAttributes(configuration, builder); } @@ -102,29 +105,58 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder .rootBeanDefinition(AuditingEventListener.class); - listenerBeanDefinitionBuilder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition( - getAuditingHandlerBeanName(), registry)); + listenerBeanDefinitionBuilder + .addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry)); registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(), AuditingEventListener.class.getName(), registry); } /** - * Register default bean definitions for a {@link MongoMappingContext} and an {@link IsNewStrategyFactory} in case we - * don't find beans with the assumed names in the registry. - * - * @param registry the {@link BeanDefinitionRegistry} to use to register the components into. - * @param source the source which the registered components shall be registered with + * Simple helper to be able to wire the {@link MappingContext} from a {@link MappingMongoConverter} bean available in + * the application context. + * + * @author Oliver Gierke */ - private void defaultDependenciesIfNecessary(BeanDefinitionRegistry registry, Object source) { + static class MongoMappingContextLookup + implements FactoryBean, MongoPersistentProperty>> { + + private final MappingMongoConverter converter; + + /** + * Creates a new {@link MongoMappingContextLookup} for the given {@link MappingMongoConverter}. + * + * @param converter must not be {@literal null}. + */ + public MongoMappingContextLookup(MappingMongoConverter converter) { + this.converter = converter; + } - if (!registry.containsBeanDefinition(MAPPING_CONTEXT_BEAN_NAME)) { + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + @Override + public MappingContext, MongoPersistentProperty> getObject() throws Exception { + return converter.getMappingContext(); + } - RootBeanDefinition definition = new RootBeanDefinition(MongoMappingContext.class); - definition.setRole(ROLE_INFRASTRUCTURE); - definition.setSource(source); + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + @Override + public Class getObjectType() { + return MappingContext.class; + } - registry.registerBeanDefinition(MAPPING_CONTEXT_BEAN_NAME, definition); + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#isSingleton() + */ + @Override + public boolean isSingleton() { + return true; } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java index 227937978..2c154948d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/config/MongoRepositoryConfigurationExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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,21 +19,15 @@ import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Collections; -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.Document; -import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.repository.MongoRepository; 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; @@ -47,8 +41,6 @@ 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#getModuleName() @@ -81,7 +73,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati */ @Override protected Collection> getIdentifyingAnnotations() { - return Collections.> singleton(Document.class); + return Collections.>singleton(Document.class); } /* @@ -90,19 +82,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati */ @Override protected Collection> getIdentifyingTypes() { - return Collections.> singleton(MongoRepository.class); - } - - /* - * (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); - } + return Collections.>singleton(MongoRepository.class); } /* @@ -130,23 +110,4 @@ 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) { - - super.registerBeansForRoot(registry, 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); - } - } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java index b6ce44ccb..288e09cb9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingViaJavaConfigRepositoriesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2016 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,8 +19,6 @@ 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; @@ -30,8 +28,6 @@ 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.MongoTemplate; -import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import org.springframework.stereotype.Repository; @@ -123,22 +119,20 @@ public class AuditingViaJavaConfigRepositoriesTests { @Configuration @EnableMongoRepositories - @EnableMongoAuditing - static class SimpleConfigWithRepositories { - - @Bean - public MongoTemplate mongoTemplate() throws UnknownHostException { - return new MongoTemplate(new SimpleMongoDbFactory(new MongoClient(), "database")); - } - } + static class SimpleConfigWithRepositories extends SimpleConfig {} @Configuration @EnableMongoAuditing - static class SimpleConfig { + static class SimpleConfig extends AbstractMongoConfiguration { - @Bean - public MongoTemplate mongoTemplate() throws UnknownHostException { - return new MongoTemplate(new SimpleMongoDbFactory(new MongoClient(), "database")); + @Override + public Mongo mongo() throws Exception { + return new MongoClient(); + } + + @Override + protected String getDatabaseName() { + return "database"; } } }