From a8a364c2deaede9f096a2a6220f1f6eb8efb9869 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 17 Jul 2020 10:40:07 +0200 Subject: [PATCH] DATAMONGO-2586 - Polishing. Add tests to ensure no reactive auditing callback is registered when using imperative configuration and vice versa. Update wording and minor code style tweaks. Original Pull Request: #877 --- .../config/PersistentEntitiesFactoryBean.java | 15 ++----- ...uditingViaJavaConfigRepositoriesTests.java | 40 ++++++++++++++----- .../mongodb/config/ReactiveAuditingTests.java | 19 +++++++++ .../asciidoc/reference/mongo-auditing.adoc | 7 ++-- 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/PersistentEntitiesFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/PersistentEntitiesFactoryBean.java index 474559228..b2045db43 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/PersistentEntitiesFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/PersistentEntitiesFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 the original author or authors. + * Copyright 2020 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. @@ -25,6 +25,8 @@ import org.springframework.data.mongodb.core.convert.MappingMongoConverter; * * @author Oliver Gierke * @author Mark Paluch + * @author Christoph Strobl + * @since 3.1 */ class PersistentEntitiesFactoryBean implements FactoryBean { @@ -44,7 +46,7 @@ class PersistentEntitiesFactoryBean implements FactoryBean { * @see org.springframework.beans.factory.FactoryBean#getObject() */ @Override - public PersistentEntities getObject() throws Exception { + public PersistentEntities getObject() { return PersistentEntities.of(converter.getMappingContext()); } @@ -56,13 +58,4 @@ class PersistentEntitiesFactoryBean implements FactoryBean { public Class getObjectType() { return PersistentEntities.class; } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#isSingleton() - */ - @Override - public boolean isSingleton() { - return true; - } } 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 27e3b05b7..24b9e9414 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 @@ -21,6 +21,7 @@ import static org.mockito.Mockito.*; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -34,12 +35,16 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; +import org.springframework.core.ResolvableType; import org.springframework.data.annotation.Version; import org.springframework.data.domain.AuditorAware; +import org.springframework.data.mapping.callback.EntityCallback; import org.springframework.data.mongodb.core.AuditablePerson; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback; +import org.springframework.data.mongodb.core.mapping.event.ReactiveAuditingEntityCallback; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import org.springframework.data.mongodb.test.util.Client; @@ -48,6 +53,7 @@ import org.springframework.data.mongodb.test.util.MongoTestUtils; import org.springframework.stereotype.Repository; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.util.ReflectionTestUtils; import com.mongodb.client.MongoClient; @@ -60,7 +66,7 @@ import com.mongodb.client.MongoClient; */ @ExtendWith({ MongoClientExtension.class, SpringExtension.class }) @ContextConfiguration -public class AuditingViaJavaConfigRepositoriesTests { +class AuditingViaJavaConfigRepositoriesTests { static @Client MongoClient mongoClient; @@ -79,6 +85,7 @@ public class AuditingViaJavaConfigRepositoriesTests { @Override protected String getDatabaseName() { + return "database"; } @@ -101,13 +108,13 @@ public class AuditingViaJavaConfigRepositoriesTests { } @BeforeEach - public void setup() { + void setup() { auditablePersonRepository.deleteAll(); this.auditor = auditablePersonRepository.save(new AuditablePerson("auditor")); } @Test // DATAMONGO-792, DATAMONGO-883 - public void basicAuditing() { + void basicAuditing() { doReturn(Optional.of(this.auditor)).when(this.auditorAware).getCurrentAuditor(); @@ -122,18 +129,18 @@ public class AuditingViaJavaConfigRepositoriesTests { @Test // DATAMONGO-843 @SuppressWarnings("resource") - public void auditingUsesFallbackMappingContextIfNoneConfiguredWithRepositories() { + void auditingUsesFallbackMappingContextIfNoneConfiguredWithRepositories() { new AnnotationConfigApplicationContext(SimpleConfigWithRepositories.class); } @Test // DATAMONGO-843 @SuppressWarnings("resource") - public void auditingUsesFallbackMappingContextIfNoneConfigured() { + void auditingUsesFallbackMappingContextIfNoneConfigured() { new AnnotationConfigApplicationContext(SimpleConfig.class); } @Test // DATAMONGO-2139 - public void auditingWorksForVersionedEntityWithWrapperVersion() { + void auditingWorksForVersionedEntityWithWrapperVersion() { verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), // it -> it.version, // @@ -143,7 +150,7 @@ public class AuditingViaJavaConfigRepositoriesTests { } @Test // DATAMONGO-2179 - public void auditingWorksForVersionedEntityBatchWithWrapperVersion() { + void auditingWorksForVersionedEntityBatchWithWrapperVersion() { verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), // it -> it.version, // @@ -153,7 +160,7 @@ public class AuditingViaJavaConfigRepositoriesTests { } @Test // DATAMONGO-2139 - public void auditingWorksForVersionedEntityWithSimpleVersion() { + void auditingWorksForVersionedEntityWithSimpleVersion() { verifyAuditingViaVersionProperty(new SimpleVersionedAuditablePerson(), // it -> it.version, // @@ -163,7 +170,7 @@ public class AuditingViaJavaConfigRepositoriesTests { } @Test // DATAMONGO-2139 - public void auditingWorksForVersionedEntityWithWrapperVersionOnTemplate() { + void auditingWorksForVersionedEntityWithWrapperVersionOnTemplate() { verifyAuditingViaVersionProperty(new VersionedAuditablePerson(), // it -> it.version, // @@ -173,7 +180,7 @@ public class AuditingViaJavaConfigRepositoriesTests { } @Test // DATAMONGO-2139 - public void auditingWorksForVersionedEntityWithSimpleVersionOnTemplate() { + void auditingWorksForVersionedEntityWithSimpleVersionOnTemplate() { verifyAuditingViaVersionProperty(new SimpleVersionedAuditablePerson(), // it -> it.version, // @@ -182,6 +189,19 @@ public class AuditingViaJavaConfigRepositoriesTests { 0L, 1L, 2L); } + @Test // DATAMONGO-2586 + void auditingShouldOnlyRegisterImperativeAuditingCallback() { + + Object callbacks = ReflectionTestUtils.getField(operations, "entityCallbacks"); + Object callbackDiscoverer = ReflectionTestUtils.getField(callbacks, "callbackDiscoverer"); + List> actualCallbacks = ReflectionTestUtils.invokeMethod(callbackDiscoverer, "getEntityCallbacks", + AuditablePerson.class, ResolvableType.forClass(EntityCallback.class)); + + assertThat(actualCallbacks) // + .hasAtLeastOneElementOfType(AuditingEntityCallback.class) // + .doesNotHaveAnyElementsOfTypes(ReactiveAuditingEntityCallback.class); + } + private void verifyAuditingViaVersionProperty(T instance, Function versionExtractor, Function createdDateExtractor, Function persister, Object... expectedValues) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java index 7f2ce737e..c4c157d18 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/ReactiveAuditingTests.java @@ -17,12 +17,18 @@ package org.springframework.data.mongodb.config; import static org.assertj.core.api.Assertions.*; +import org.springframework.core.ResolvableType; +import org.springframework.data.mapping.callback.EntityCallback; +import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback; +import org.springframework.data.mongodb.core.mapping.event.ReactiveAuditingEntityCallback; +import org.springframework.test.util.ReflectionTestUtils; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @@ -146,6 +152,19 @@ class ReactiveAuditingTests { 0L, 1L, 2L); } + @Test // DATAMONGO-2586 + void auditingShouldOnlyRegisterReactiveAuditingCallback() { + + Object callbacks = ReflectionTestUtils.getField(operations, "entityCallbacks"); + Object callbackDiscoverer = ReflectionTestUtils.getField(callbacks, "callbackDiscoverer"); + List> actualCallbacks = ReflectionTestUtils.invokeMethod(callbackDiscoverer, "getEntityCallbacks", + AuditablePerson.class, ResolvableType.forClass(EntityCallback.class)); + + assertThat(actualCallbacks) // + .hasAtLeastOneElementOfType(ReactiveAuditingEntityCallback.class) // + .doesNotHaveAnyElementsOfTypes(AuditingEntityCallback.class); + } + private void verifyAuditingViaVersionProperty(T instance, Function versionExtractor, Function createdDateExtractor, Function> persister, Object... expectedValues) { diff --git a/src/main/asciidoc/reference/mongo-auditing.adoc b/src/main/asciidoc/reference/mongo-auditing.adoc index b7abbe711..2b1ae3831 100644 --- a/src/main/asciidoc/reference/mongo-auditing.adoc +++ b/src/main/asciidoc/reference/mongo-auditing.adoc @@ -30,9 +30,10 @@ To activate auditing functionality via XML, add the Spring Data Mongo `auditing` ---- ==== -If you wish to use auditing with the reactive programming model, then enable auditing through `@EnableReactiveMongoAuditing` +To enable auditing, leveraging a reactive programming model, use the `@EnableReactiveMongoAuditing` annotation. + +If you expose a bean of type `ReactiveAuditorAware` to the `ApplicationContext`, the auditing infrastructure picks it up automatically and uses it to determine the current user to be set on domain types. If you have multiple implementations registered in the `ApplicationContext`, you can select the one to be used by explicitly setting the `auditorAwareRef` attribute of `@EnableReactiveMongoAuditing`. -.Activating auditing using JavaConfig +.Activating reactive auditing using JavaConfig ==== [source,java] ---- @@ -47,5 +48,5 @@ class Config { } ---- ==== -If you expose a bean of type `ReactiveAuditorAware` to the `ApplicationContext`, the auditing infrastructure picks it up automatically and uses it to determine the current user to be set on domain types. If you have multiple implementations registered in the `ApplicationContext`, you can select the one to be used by explicitly setting the `auditorAwareRef` attribute of `@EnableReactiveMongoAuditing`. +