diff --git a/pom.xml b/pom.xml index 253b26b609..e741100906 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-commons - 4.1.0-SNAPSHOT + 4.1.0-GH-3441-SNAPSHOT Spring Data Core Core Spring concepts underpinning every Spring Data module. diff --git a/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java b/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java index c6063ec0c1..3cd89df7cf 100644 --- a/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java +++ b/src/main/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactory.java @@ -71,6 +71,9 @@ public MappingAuditableBeanWrapperFactory(PersistentEntities entities) { this.entities = entities; this.metadataCache = new ConcurrentHashMap<>(); + + entities + .forEach(it -> entities.mapOnContext(it.getType(), (context, entity) -> getMetadata(context, it.getType()))); } @Override @@ -82,20 +85,26 @@ public Optional> getBeanWrapperFor(T source) { return super.getBeanWrapperFor(source); } - return entities.mapOnContext(it.getClass(), (context, entity) -> { + Class entityClass = it.getClass(); + return entities.mapOnContext(entityClass, (context, entity) -> { - MappingAuditingMetadata metadata = metadataCache.computeIfAbsent(it.getClass(), - key -> new MappingAuditingMetadata(context, it.getClass())); + MappingAuditingMetadata metadata = getMetadata(context, entityClass); - return Optional.> ofNullable(metadata.isAuditable() // - ? new MappingMetadataAuditableBeanWrapper<>(getConversionService(), entity.getPropertyPathAccessor(it), - metadata) - : null); + if (metadata.isAuditable()) { + return Optional.> of(new MappingMetadataAuditableBeanWrapper<>(getConversionService(), + entity.getPropertyPathAccessor(it), metadata)); + } + return Optional.> empty(); }).orElseGet(() -> super.getBeanWrapperFor(source)); }); } + private MappingAuditingMetadata getMetadata(MappingContext> context, + Class entityClass) { + return metadataCache.computeIfAbsent(entityClass, key -> new MappingAuditingMetadata(context, entityClass)); + } + /** * Captures {@link PersistentProperty} instances equipped with auditing annotations. * diff --git a/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java b/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java index 4fcf225805..764bc9f9a7 100644 --- a/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java +++ b/src/main/java/org/springframework/data/mapping/context/PersistentEntities.java @@ -136,7 +136,7 @@ public static PersistentEntities of(MappingContext... contexts) { * @return result of the {@link BiFunction}. */ public Optional mapOnContext(Class type, - BiFunction>, PersistentEntity, T> combiner) { + BiFunction>, PersistentEntity, @Nullable T> combiner) { Assert.notNull(type, "Type must not be null"); Assert.notNull(combiner, "Combining BiFunction must not be null"); @@ -144,16 +144,21 @@ public Optional mapOnContext(Class type, Collection>> mappingContexts = getMappingContexts(); if (mappingContexts.size() == 1) { - return mappingContexts.stream() // - .filter(it -> it.getPersistentEntity(type) != null) // - .map(it -> combiner.apply(it, it.getRequiredPersistentEntity(type))) // - .findFirst(); + for (MappingContext> it : mappingContexts) { + if (it.getPersistentEntity(type) != null) { + return Optional.ofNullable(combiner.apply(it, it.getRequiredPersistentEntity(type))); + } + } + return Optional.empty(); + } + + for (MappingContext> it : mappingContexts) { + if (it.hasPersistentEntityFor(type)) { + return Optional.ofNullable(combiner.apply(it, it.getRequiredPersistentEntity(type))); + } } - return mappingContexts.stream() // - .filter(it -> it.hasPersistentEntityFor(type)) // - .map(it -> combiner.apply(it, it.getRequiredPersistentEntity(type))) // - .findFirst(); + return Optional.empty(); } /** diff --git a/src/test/java/org/springframework/data/auditing/IsNewAwareAuditingHandlerUnitTests.java b/src/test/java/org/springframework/data/auditing/IsNewAwareAuditingHandlerUnitTests.java index a0558968b2..cd361bf936 100755 --- a/src/test/java/org/springframework/data/auditing/IsNewAwareAuditingHandlerUnitTests.java +++ b/src/test/java/org/springframework/data/auditing/IsNewAwareAuditingHandlerUnitTests.java @@ -20,12 +20,12 @@ import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; + import org.springframework.data.annotation.Id; import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.mapping.context.SampleMappingContext; @@ -34,24 +34,18 @@ * Unit test for {@code AuditingHandler}. * * @author Oliver Gierke + * @author Mark Paluch * @since 1.5 */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) class IsNewAwareAuditingHandlerUnitTests extends AuditingHandlerUnitTests { - SampleMappingContext mappingContext; - - @BeforeEach - void init() { - - this.mappingContext = new SampleMappingContext(); - this.mappingContext.getPersistentEntity(AuditedUser.class); - this.mappingContext.afterPropertiesSet(); - } - @Override protected IsNewAwareAuditingHandler getHandler() { + SampleMappingContext mappingContext = new SampleMappingContext(); + mappingContext.getPersistentEntity(AuditedUser.class); + mappingContext.afterPropertiesSet(); return new IsNewAwareAuditingHandler(PersistentEntities.of(mappingContext)); } diff --git a/src/test/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactoryUnitTests.java b/src/test/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactoryUnitTests.java index 7c47d526ca..7df681a3fc 100755 --- a/src/test/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/auditing/MappingAuditableBeanWrapperFactoryUnitTests.java @@ -45,12 +45,14 @@ import org.springframework.data.domain.Auditable; import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.mapping.context.SampleMappingContext; +import org.springframework.test.util.ReflectionTestUtils; /** * Unit tests for {@link MappingAuditableBeanWrapperFactory}. * * @author Oliver Gierke * @author Jens Schauder + * @author Mark Paluch * @since 1.8 */ class MappingAuditableBeanWrapperFactoryUnitTests { @@ -69,6 +71,13 @@ void setUp() { factory = new MappingAuditableBeanWrapperFactory(entities); } + @Test // GH-3441 + void cacheWarmedWithKnownPersistentEntities() { + + Map metadataCache = (Map) ReflectionTestUtils.getField(factory, "metadataCache"); + assertThat(metadataCache).hasSize(4); + } + @Test // DATACMNS-365 void discoversAuditingPropertyOnField() {