From f6db714206a78b2321dcf1905108aac7ee1a853f Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 30 Nov 2016 15:45:26 +0100 Subject: [PATCH] DATACMNS-928 - Refinements for aggregate root domain event publication. We now publish events for all methods named "save" on the repository. Fundamentally, that's in place to capture calls to CrudRepository.save(Iterable entities), too. Some minor refactorings to the internal setup of EventPublishingMethodInterceptor. More JavaDoc. --- ...ublishingRepositoryProxyPostProcessor.java | 26 +++++++++++----- ...RepositoryProxyPostProcessorUnitTests.java | 30 +++++++++++++++---- 2 files changed, 43 insertions(+), 13 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 e517c69dc..90200607d 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 @@ -65,14 +65,18 @@ public class EventPublishingRepositoryProxyPostProcessor implements RepositoryPr return; } - factory.addAdvice(new EventPublishingMethodInterceptor(repositoryInformation.getCrudMethods().getSaveMethod(), - method, publisher)); + factory.addAdvice(new EventPublishingMethodInterceptor(method, publisher)); } - @RequiredArgsConstructor + /** + * {@link MethodInterceptor} to publish events exposed an aggregate on calls to a save method on the repository. + * + * @author Oliver Gierke + * @since 1.13 + */ + @RequiredArgsConstructor(staticName = "of") static class EventPublishingMethodInterceptor implements MethodInterceptor { - private final Method saveMethod; private final EventPublishingMethod eventMethod; private final ApplicationEventPublisher publisher; @@ -83,7 +87,7 @@ public class EventPublishingRepositoryProxyPostProcessor implements RepositoryPr @Override public Object invoke(MethodInvocation invocation) throws Throwable { - if (!invocation.getMethod().equals(saveMethod)) { + if (!invocation.getMethod().getName().equals("save")) { return invocation.proceed(); } @@ -95,6 +99,12 @@ public class EventPublishingRepositoryProxyPostProcessor implements RepositoryPr } } + /** + * Abstraction of a method on the aggregate root that exposes the events to publish. + * + * @author Oliver Gierke + * @since 1.13 + */ @RequiredArgsConstructor static class EventPublishingMethod { @@ -151,8 +161,10 @@ public class EventPublishingRepositoryProxyPostProcessor implements RepositoryPr return; } - for (Object event : asCollection(ReflectionUtils.invokeMethod(publishingMethod, object))) { - publisher.publishEvent(event); + for (Object aggregateRoot : asCollection(object)) { + for (Object event : asCollection(ReflectionUtils.invokeMethod(publishingMethod, aggregateRoot))) { + publisher.publishEvent(event); + } } if (clearingMethod != null) { 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 8030d4028..a4953a65b 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 @@ -25,7 +25,6 @@ import lombok.Getter; import lombok.Value; import java.io.Serializable; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.UUID; @@ -129,14 +128,14 @@ public class EventPublishingRepositoryProxyPostProcessorUnitTests { @Test public void interceptsSaveMethod() throws Throwable { - Method saveMethod = SampleRepository.class.getMethod("save", Object.class); - doReturn(saveMethod).when(invocation).getMethod(); + doReturn(SampleRepository.class.getMethod("save", Object.class)).when(invocation).getMethod(); SomeEvent event = new SomeEvent(); MultipleEvents sample = MultipleEvents.of(Arrays.asList(event)); doReturn(new Object[] { sample }).when(invocation).getArguments(); - new EventPublishingMethodInterceptor(saveMethod, EventPublishingMethod.of(MultipleEvents.class), publisher) + EventPublishingMethodInterceptor// + .of(EventPublishingMethod.of(MultipleEvents.class), publisher)// .invoke(invocation); verify(publisher).publishEvent(event); @@ -148,10 +147,10 @@ public class EventPublishingRepositoryProxyPostProcessorUnitTests { @Test public void doesNotInterceptNonSaveMethod() throws Throwable { - Method saveMethod = SampleRepository.class.getMethod("save", Object.class); doReturn(SampleRepository.class.getMethod("findOne", Serializable.class)).when(invocation).getMethod(); - new EventPublishingMethodInterceptor(saveMethod, EventPublishingMethod.of(MultipleEvents.class), publisher) + EventPublishingMethodInterceptor// + .of(EventPublishingMethod.of(MultipleEvents.class), publisher)// .invoke(invocation); verify(publisher, never()).publishEvent(any()); @@ -189,6 +188,25 @@ public class EventPublishingRepositoryProxyPostProcessorUnitTests { verify(factory, never()).addAdvice(any(Advice.class)); } + /** + * @see DATACMNS-928 + */ + @Test + public void publishesEventsForCallToSaveWithIterable() throws Throwable { + + SomeEvent event = new SomeEvent(); + MultipleEvents sample = MultipleEvents.of(Arrays.asList(event)); + doReturn(new Object[] { Arrays.asList(sample) }).when(invocation).getArguments(); + + doReturn(SampleRepository.class.getMethod("save", Iterable.class)).when(invocation).getMethod(); + + EventPublishingMethodInterceptor// + .of(EventPublishingMethod.of(MultipleEvents.class), publisher)// + .invoke(invocation); + + verify(publisher).publishEvent(any(SomeEvent.class)); + } + @Value(staticConstructor = "of") static class MultipleEvents { @Getter(onMethod = @__(@DomainEvents)) Collection events;