Skip to content

Commit 8a7976f

Browse files
committed
DATAREST-970 - AnnotationEventHandlerInvoker now considers order of event handler methods.
We now make sure that an @order annotation on annotated event handler methods are considered and the methods are invoked in the defined order. Non-annotation-based event handlers don't suffer from the same problem as they're ApplicationListener instances directly so that the container will enforce the correct ordering in case @order is used or Ordered is implemented. Some cleanup in EventHandlerMethod. Original pull request: #248.
1 parent 0cd27b9 commit 8a7976f

File tree

2 files changed

+81
-14
lines changed

2 files changed

+81
-14
lines changed

spring-data-rest-core/src/main/java/org/springframework/data/rest/core/event/AnnotatedEventHandlerInvoker.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2014 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,9 +15,14 @@
1515
*/
1616
package org.springframework.data.rest.core.event;
1717

18+
import lombok.EqualsAndHashCode;
19+
import lombok.RequiredArgsConstructor;
20+
import lombok.ToString;
21+
1822
import java.lang.annotation.Annotation;
1923
import java.lang.reflect.Method;
2024
import java.util.ArrayList;
25+
import java.util.Collections;
2126
import java.util.List;
2227

2328
import org.slf4j.Logger;
@@ -26,6 +31,7 @@
2631
import org.springframework.beans.factory.config.BeanPostProcessor;
2732
import org.springframework.context.ApplicationEvent;
2833
import org.springframework.context.ApplicationListener;
34+
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
2935
import org.springframework.core.annotation.AnnotationUtils;
3036
import org.springframework.data.rest.core.annotation.HandleAfterCreate;
3137
import org.springframework.data.rest.core.annotation.HandleAfterDelete;
@@ -165,37 +171,50 @@ private <T extends Annotation> void inspect(Object handler, Method method, Class
165171
throw new IllegalStateException(String.format(PARAMETER_MISSING, method));
166172
}
167173

168-
EventHandlerMethod handlerMethod = new EventHandlerMethod(parameterTypes[0], handler, method);
174+
EventHandlerMethod handlerMethod = EventHandlerMethod.of(parameterTypes[0], handler, method);
169175

170176
if (LOG.isDebugEnabled()) {
171177
LOG.debug("Annotated handler method found: {}", handlerMethod);
172178
}
173179

174-
handlerMethods.add(eventType, handlerMethod);
180+
List<EventHandlerMethod> events = handlerMethods.get(eventType);
181+
182+
if (events == null) {
183+
events = new ArrayList<EventHandlerMethod>();
184+
}
185+
186+
if (events.isEmpty()) {
187+
handlerMethods.add(eventType, handlerMethod);
188+
return;
189+
}
190+
191+
events.add(handlerMethod);
192+
Collections.sort(events);
193+
handlerMethods.put(eventType, events);
175194
}
176195

177-
static class EventHandlerMethod {
196+
@ToString
197+
@EqualsAndHashCode
198+
@RequiredArgsConstructor
199+
static class EventHandlerMethod implements Comparable<EventHandlerMethod> {
178200

179201
final Class<?> targetType;
180202
final Method method;
181203
final Object handler;
182204

183-
private EventHandlerMethod(Class<?> targetType, Object handler, Method method) {
184-
185-
this.targetType = targetType;
186-
this.method = method;
187-
this.handler = handler;
205+
public static EventHandlerMethod of(Class<?> targetType, Object handler, Method method) {
188206

189-
ReflectionUtils.makeAccessible(this.method);
207+
ReflectionUtils.makeAccessible(method);
208+
return new EventHandlerMethod(targetType, method, handler);
190209
}
191210

192-
/*
211+
/*
193212
* (non-Javadoc)
194-
* @see java.lang.Object#toString()
213+
* @see java.lang.Comparable#compareTo(java.lang.Object)
195214
*/
196215
@Override
197-
public String toString() {
198-
return String.format("EventHandlerMethod{ targetType=%s, method=%s, handler=%s }", targetType, method, handler);
216+
public int compareTo(EventHandlerMethod o) {
217+
return AnnotationAwareOrderComparator.INSTANCE.compare(this.method, o.method);
199218
}
200219
}
201220
}

spring-data-rest-core/src/test/java/org/springframework/data/rest/core/event/AnnotatedEventHandlerInvokerUnitTests.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.junit.Test;
2222
import org.springframework.aop.framework.ProxyFactory;
23+
import org.springframework.core.annotation.Order;
2324
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
2425
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
2526
import org.springframework.data.rest.core.domain.Person;
@@ -32,6 +33,7 @@
3233
*
3334
* @author Oliver Gierke
3435
* @author Fabian Trampusch
36+
* @author Joseph Valerio
3537
*/
3638
public class AnnotatedEventHandlerInvokerUnitTests {
3739

@@ -71,6 +73,24 @@ public void invokesPrivateEventHandlerMethods() {
7173
assertThat(sampleHandler.wasCalled, is(true));
7274
}
7375

76+
@Test // DATAREST-970
77+
public void invokesEventHandlerInOrderMethods() {
78+
79+
SampleOrderEventHandler1 orderHandler1 = new SampleOrderEventHandler1();
80+
SampleOrderEventHandler2 orderHandler2 = new SampleOrderEventHandler2();
81+
82+
AnnotatedEventHandlerInvoker invoker = new AnnotatedEventHandlerInvoker();
83+
invoker.postProcessAfterInitialization(orderHandler1, "orderHandler1");
84+
invoker.postProcessAfterInitialization(orderHandler2, "orderHandler2");
85+
86+
invoker.onApplicationEvent(new BeforeCreateEvent(new Person("Dave", "Matthews")));
87+
88+
assertThat(orderHandler1.wasCalled, is(true));
89+
assertThat(orderHandler2.wasCalled, is(true));
90+
91+
assertThat(orderHandler1.timestamp, is(greaterThan(orderHandler2.timestamp)));
92+
}
93+
7494
@RepositoryEventHandler
7595
static class Sample {
7696

@@ -88,4 +108,32 @@ private void method(Person sample) {
88108
wasCalled = true;
89109
}
90110
}
111+
112+
@RepositoryEventHandler
113+
static class SampleOrderEventHandler1 {
114+
115+
boolean wasCalled = false;
116+
long timestamp;
117+
118+
@Order(2)
119+
@HandleBeforeCreate
120+
private void method(Person sample) {
121+
wasCalled = true;
122+
timestamp = System.nanoTime();
123+
}
124+
}
125+
126+
@RepositoryEventHandler
127+
static class SampleOrderEventHandler2 {
128+
129+
boolean wasCalled = false;
130+
long timestamp;
131+
132+
@Order(1)
133+
@HandleBeforeCreate
134+
private void method(Person sample) {
135+
wasCalled = true;
136+
timestamp = System.nanoTime();
137+
}
138+
}
91139
}

0 commit comments

Comments
 (0)