Polishing.

Adopt to Framework changes.
Simplify auditing bean registration.
Remove ImportRuntimeHints in EnableMongoAuditing.
Refine ManagedTypes bean definitions.
Consistently use mongo as bean name prefix. Depend on store-specific ManagedTypes.
Rewrite ReactiveMongoAuditingRegistrar to avoid inner beans.
Reduce AOT processor visibility. Cleanup imports. Improve type naming. Update Javadoc.

Original Pull Request: #4093
This commit is contained in:
Mark Paluch
2022-06-29 15:20:58 +02:00
committed by Christoph Strobl
parent cfd55be95b
commit d334c5a44c
16 changed files with 128 additions and 70 deletions

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb;
import java.util.Arrays;
import java.util.function.Consumer;
import org.springframework.data.domain.ManagedTypes;
@@ -27,19 +28,49 @@ public final class MongoManagedTypes implements ManagedTypes {
private final ManagedTypes delegate;
public MongoManagedTypes(ManagedTypes types) {
private MongoManagedTypes(ManagedTypes types) {
this.delegate = types;
}
/**
* Wraps an existing {@link ManagedTypes} object with {@link MongoManagedTypes}.
*
* @param managedTypes
* @return
*/
public static MongoManagedTypes from(ManagedTypes managedTypes) {
return new MongoManagedTypes(managedTypes);
}
public static MongoManagedTypes of(Iterable<? extends Class<?>> types) {
/**
* Factory method used to construct {@link MongoManagedTypes} from the given array of {@link Class types}.
*
* @param types array of {@link Class types} used to initialize the {@link ManagedTypes}; must not be {@literal null}.
* @return new instance of {@link MongoManagedTypes} initialized from {@link Class types}.
*/
public static MongoManagedTypes from(Class<?>... types) {
return fromIterable(Arrays.asList(types));
}
/**
* Factory method used to construct {@link MongoManagedTypes} from the given, required {@link Iterable} of
* {@link Class types}.
*
* @param types {@link Iterable} of {@link Class types} used to initialize the {@link ManagedTypes}; must not be
* {@literal null}.
* @return new instance of {@link MongoManagedTypes} initialized the given, required {@link Iterable} of {@link Class
* types}.
*/
public static MongoManagedTypes fromIterable(Iterable<? extends Class<?>> types) {
return from(ManagedTypes.fromIterable(types));
}
public static MongoManagedTypes none() {
/**
* Factory method to return an empty {@link MongoManagedTypes} object.
*
* @return an empty {@link MongoManagedTypes} object.
*/
public static MongoManagedTypes empty() {
return from(ManagedTypes.empty());
}

View File

@@ -27,7 +27,7 @@ import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
*/
public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotProcessor {
private LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
private final LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
@Override
protected void contribute(AotRepositoryContext repositoryContext, GenerationContext generationContext) {

View File

@@ -36,7 +36,7 @@ import org.springframework.data.mongodb.core.mapping.DocumentReference;
* @author Christoph Strobl
* @since 4.0
*/
public class LazyLoadingProxyAotProcessor {
class LazyLoadingProxyAotProcessor {
private boolean generalLazyLoadingProxyContributed = false;

View File

@@ -26,9 +26,9 @@ import org.springframework.util.ClassUtils;
* @author Christoph Strobl
* @since 2022/06
*/
public class MongoManagedTypesBeanRegistrationAotProcessor extends ManagedTypesBeanRegistrationAotProcessor {
class MongoManagedTypesBeanRegistrationAotProcessor extends ManagedTypesBeanRegistrationAotProcessor {
private LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
private final LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
public MongoManagedTypesBeanRegistrationAotProcessor() {
setModuleIdentifier("mongo");

View File

@@ -25,14 +25,26 @@ import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.AfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveAfterSaveCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.ReactiveBeforeSaveCallback;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRepository;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.lang.Nullable;
/**
* {@link RuntimeHintsRegistrar} for repository types and entity callbacks.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 4.0
*/
public class DataMongoRuntimeHints implements RuntimeHintsRegistrar {
class MongoRuntimeHints implements RuntimeHintsRegistrar {
private static final boolean PROJECT_REACTOR_PRESENT = ReactiveWrappers
.isAvailable(ReactiveWrappers.ReactiveLibrary.PROJECT_REACTOR);
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
@@ -43,5 +55,15 @@ public class DataMongoRuntimeHints implements RuntimeHintsRegistrar {
TypeReference.of(AfterSaveCallback.class)),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_METHODS));
if (PROJECT_REACTOR_PRESENT) {
hints.reflection()
.registerTypes(Arrays.asList(TypeReference.of(SimpleReactiveMongoRepository.class),
TypeReference.of(ReactiveBeforeConvertCallback.class), TypeReference.of(ReactiveBeforeSaveCallback.class),
TypeReference.of(ReactiveAfterConvertCallback.class), TypeReference.of(ReactiveAfterSaveCallback.class)),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_METHODS));
}
}
}

View File

@@ -80,10 +80,10 @@ public abstract class AbstractMongoClientConfiguration extends MongoConfiguratio
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
* {@link #mongoMappingContext(MongoCustomConversions)}. Will get {@link #customConversions()} applied.
* {@link #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext(MongoCustomConversions)
* @see #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)
* @see #mongoDbFactory()
*/
@Bean

View File

@@ -84,10 +84,10 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
/**
* Creates a {@link MappingMongoConverter} using the configured {@link #reactiveMongoDbFactory()} and
* {@link #mongoMappingContext(MongoCustomConversions)}. Will get {@link #customConversions()} applied.
* {@link #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)}. Will get {@link #customConversions()} applied.
*
* @see #customConversions()
* @see #mongoMappingContext(MongoCustomConversions)
* @see #mongoMappingContext(MongoCustomConversions, org.springframework.data.mongodb.MongoManagedTypes)
* @see #reactiveMongoDbFactory()
* @return never {@literal null}.
*/

View File

@@ -23,8 +23,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.data.aot.hint.AuditingHints;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.domain.AuditorAware;
@@ -39,7 +37,6 @@ import org.springframework.data.domain.AuditorAware;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MongoAuditingRegistrar.class)
@ImportRuntimeHints(AuditingHints.AuditingRuntimeHints.class)
public @interface EnableMongoAuditing {
/**

View File

@@ -17,20 +17,20 @@ package org.springframework.data.mongodb.config;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
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.mapping.context.PersistentEntities;
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -52,35 +52,10 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport impl
return "mongoAuditingHandler";
}
String persistentEntitiesBeanName;
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if(persistentEntitiesBeanName == null) {
if (registry instanceof DefaultListableBeanFactory beanFactory) {
for (String bn : beanFactory.getBeanNamesForType(PersistentEntities.class)) {
if (bn.startsWith("mongo")) {
persistentEntitiesBeanName = bn;
}
}
}
if(persistentEntitiesBeanName == null) {
persistentEntitiesBeanName = BeanDefinitionReaderUtils.uniqueBeanName("mongo.persistent-entities", registry);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntities.class)
.setFactoryMethod("of")
//.addConstructorArgValue(new RuntimeBeanReference(MongoMappingContext.class))
.addConstructorArgReference("mongoMappingContext");
registry.registerBeanDefinition(persistentEntitiesBeanName, definition.getBeanDefinition());
}
}
super.registerBeanDefinitions(annotationMetadata, registry);
protected void postProcess(BeanDefinitionBuilder builder, AuditingConfiguration configuration,
BeanDefinitionRegistry registry) {
potentiallyRegisterMongoPersistentEntities(builder, registry);
}
@Override
@@ -88,9 +63,8 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport impl
Assert.notNull(configuration, "AuditingConfiguration must not be null");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
builder.addConstructorArgReference(persistentEntitiesBeanName);
return configureDefaultAuditHandlerAttributes(configuration, builder);
return configureDefaultAuditHandlerAttributes(configuration,
BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class));
}
@Override
@@ -109,9 +83,42 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport impl
AuditingEntityCallback.class.getName(), registry);
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
static void potentiallyRegisterMongoPersistentEntities(BeanDefinitionBuilder builder,
BeanDefinitionRegistry registry) {
String persistentEntitiesBeanName = MongoAuditingRegistrar.detectPersistentEntitiesBeanName(registry);
if (persistentEntitiesBeanName == null) {
persistentEntitiesBeanName = BeanDefinitionReaderUtils.uniqueBeanName("mongoPersistentEntities", registry);
// TODO: https://github.com/spring-projects/spring-framework/issues/28728
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntities.class) //
.setFactoryMethod("of") //
.addConstructorArgReference("mongoMappingContext");
registry.registerBeanDefinition(persistentEntitiesBeanName, definition.getBeanDefinition());
}
builder.addConstructorArgReference(persistentEntitiesBeanName);
}
@Nullable
private static String detectPersistentEntitiesBeanName(BeanDefinitionRegistry registry) {
if (registry instanceof ListableBeanFactory beanFactory) {
for (String bn : beanFactory.getBeanNamesForType(PersistentEntities.class)) {
if (bn.startsWith("mongo")) {
return bn;
}
}
}
return null;
}
}

View File

@@ -78,14 +78,13 @@ public abstract class MongoConfigurationSupport {
*
* @see #getMappingBasePackages()
* @return
* @throws ClassNotFoundException
*/
@Bean
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions, ManagedTypes managedTypes)
throws ClassNotFoundException {
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions,
MongoManagedTypes mongoManagedTypes) {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setManagedTypes(managedTypes);
mappingContext.setManagedTypes(mongoManagedTypes);
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
mappingContext.setAutoIndexCreation(autoIndexCreation());
@@ -99,8 +98,8 @@ public abstract class MongoConfigurationSupport {
* @since 4.0
*/
@Bean
public MongoManagedTypes managedTypes() throws ClassNotFoundException {
return MongoManagedTypes.of(getInitialEntitySet());
public MongoManagedTypes mongoManagedTypes() throws ClassNotFoundException {
return MongoManagedTypes.fromIterable(getInitialEntitySet());
}
/**

View File

@@ -18,11 +18,9 @@ package org.springframework.data.mongodb.config;
import java.lang.annotation.Annotation;
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.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.auditing.ReactiveIsNewAwareAuditingHandler;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
@@ -48,18 +46,19 @@ class ReactiveMongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupp
return "reactiveMongoAuditingHandler";
}
@Override
protected void postProcess(BeanDefinitionBuilder builder, AuditingConfiguration configuration,
BeanDefinitionRegistry registry) {
MongoAuditingRegistrar.potentiallyRegisterMongoPersistentEntities(builder, registry);
}
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
Assert.notNull(configuration, "AuditingConfiguration must not be null");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveIsNewAwareAuditingHandler.class);
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntitiesFactoryBean.class);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
builder.addConstructorArgValue(definition.getBeanDefinition());
return configureDefaultAuditHandlerAttributes(configuration, builder);
return configureDefaultAuditHandlerAttributes(configuration,
BeanDefinitionBuilder.rootBeanDefinition(ReactiveIsNewAwareAuditingHandler.class));
}
@Override

View File

@@ -31,7 +31,7 @@ import org.springframework.data.repository.config.AnnotationRepositoryConfigurat
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.lang.NonNull;
import org.w3c.dom.Element;
/**

View File

@@ -1,4 +1,5 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
org.springframework.data.mongodb.aot.DataMongoRuntimeHints
org.springframework.data.mongodb.aot.MongoRuntimeHints
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
org.springframework.data.mongodb.aot.MongoManagedTypesBeanRegistrationAotProcessor

View File

@@ -87,7 +87,7 @@ public class RepositoryRegistrationAotContributionAssert
BeanRegistrationCode mockBeanRegistrationCode = mock(BeanRegistrationCode.class);
DefaultGenerationContext generationContext =
new DefaultGenerationContext(new ClassNameGenerator(), new InMemoryGeneratedFiles(), new RuntimeHints());
new DefaultGenerationContext(new ClassNameGenerator(Object.class), new InMemoryGeneratedFiles());
this.actual.applyTo(generationContext, mockBeanRegistrationCode);

View File

@@ -93,7 +93,8 @@ public class AbstractMongoConfigurationUnitTests {
public void returnsUninitializedMappingContext() throws Exception {
SampleMongoConfiguration configuration = new SampleMongoConfiguration();
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions(), MongoManagedTypes.of(Collections.singleton(Entity.class)));
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions(),
MongoManagedTypes.from(Entity.class));
assertThat(context.getPersistentEntities()).isEmpty();
context.initialize();

View File

@@ -27,6 +27,7 @@ import java.util.Set;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -38,7 +39,6 @@ import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MongoTypeMapper;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
@@ -93,7 +93,8 @@ public class AbstractReactiveMongoConfigurationUnitTests {
public void returnsUninitializedMappingContext() throws Exception {
SampleMongoConfiguration configuration = new SampleMongoConfiguration();
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions(), MongoManagedTypes.of(Collections.singleton(Entity.class)));
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions(),
MongoManagedTypes.from(Entity.class));
assertThat(context.getPersistentEntities()).isEmpty();
context.initialize();