From dcb1ee61eb7269e53b2733874fdc2b09063a7aac Mon Sep 17 00:00:00 2001 From: yukiyoshida Date: Mon, 15 May 2017 15:44:27 +0900 Subject: [PATCH] DATACMNS-1067 - Fix not to call @AfterDomainEventPublication method from collection of entities. We now make sure the event cleanup method is called on the aggregate root, not on the parameter object directly (as the latter might be a collection. Original pull request: #216. --- ...ublishingRepositoryProxyPostProcessor.java | 11 +++-- ...RepositoryProxyPostProcessorUnitTests.java | 46 +++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java b/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java index 3079e2112..ea6486cc8 100644 --- a/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java +++ b/src/main/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessor.java @@ -44,6 +44,8 @@ import org.springframework.util.ReflectionUtils; * will be invoked after all events have been published. * * @author Oliver Gierke + * @author Christoph Strobl + * @author Yuki Yoshida * @since 1.13 * @soundtrack Henrik Freischlader Trio - Master Plan (Openness) */ @@ -164,13 +166,14 @@ public class EventPublishingRepositoryProxyPostProcessor implements RepositoryPr } for (Object aggregateRoot : asCollection(object)) { - for (Object event : asCollection(ReflectionUtils.invokeMethod(publishingMethod, aggregateRoot))) { + Collection events = asCollection(ReflectionUtils.invokeMethod(publishingMethod, aggregateRoot)); + for (Object event : events) { publisher.publishEvent(event); } - } - if (clearingMethod != null) { - ReflectionUtils.invokeMethod(clearingMethod, object); + if (clearingMethod != null && !events.isEmpty()) { + ReflectionUtils.invokeMethod(clearingMethod, aggregateRoot); + } } } diff --git a/src/test/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessorUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessorUnitTests.java index 2e854db77..1fa71e2b9 100644 --- a/src/test/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/EventPublishingRepositoryProxyPostProcessorUnitTests.java @@ -22,6 +22,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Value; import java.io.Serializable; @@ -39,6 +40,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.domain.AfterDomainEventPublication; import org.springframework.data.domain.DomainEvents; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.core.RepositoryInformation; @@ -49,6 +51,8 @@ import org.springframework.data.repository.core.support.EventPublishingRepositor * Unit tests for {@link EventPublishingRepositoryProxyPostProcessor} and contained classes. * * @author Oliver Gierke + * @author Mark Paluch + * @author Yuki Yoshida * @soundtrack Henrik Freischlader Trio - Nobody Else To Blame (Openness) */ @RunWith(MockitoJUnitRunner.class) @@ -101,6 +105,40 @@ public class EventPublishingRepositoryProxyPostProcessorUnitTests { verify(publisher, times(0)).publishEvent(any()); } + @Test // DATACMNS-1067 + public void clearEventsDoesNotExposedByEntity() { + + EventsWithClearing entity = spy(EventsWithClearing.of(Collections.emptyList())); + + EventPublishingMethod.of(EventsWithClearing.class).publishEventsFrom(entity, publisher); + + verify(entity, times(0)).clearDomainEvents(); + } + + @Test // DATACMNS-1067 + public void clearEventsExposedByEntity() { + + EventsWithClearing entity = spy(EventsWithClearing.of(Collections.singletonList(new SomeEvent()))); + + EventPublishingMethod.of(EventsWithClearing.class).publishEventsFrom(entity, publisher); + + verify(entity, times(1)).clearDomainEvents(); + } + + @Test // DATACMNS-1067 + public void clearEventsExposedByEntities() { + + EventsWithClearing firstEntity = spy(EventsWithClearing.of(Collections.emptyList())); + EventsWithClearing secondEntity = spy(EventsWithClearing.of(Collections.singletonList(new SomeEvent()))); + + Collection entities = Arrays.asList(firstEntity, secondEntity); + + EventPublishingMethod.of(EventsWithClearing.class).publishEventsFrom(entities, publisher); + + verify(firstEntity, times(0)).clearDomainEvents(); + verify(secondEntity, times(1)).clearDomainEvents(); + } + @Test // DATACMNS-928 public void doesNotCreatePublishingMethodIfNoAnnotationDetected() { assertThat(EventPublishingMethod.of(Object.class), is(nullValue())); @@ -215,6 +253,14 @@ public class EventPublishingRepositoryProxyPostProcessorUnitTests { @Getter(onMethod = @__(@DomainEvents)) Collection events; } + @RequiredArgsConstructor(staticName = "of") + static class EventsWithClearing { + @Getter(onMethod = @__(@DomainEvents)) final Collection events; + + @AfterDomainEventPublication + void clearDomainEvents() {} + } + @Value(staticConstructor = "of") static class OneEvent { @Getter(onMethod = @__(@DomainEvents)) Object event;