Support for multiple events per method

In addition to specifying the event type to listen to via a method
parameter, any @EventListener annotated method can now alternatively
define the event type(s) to listen to via the "classes" attributes (that
is aliased to "value").

Something like

@EventListener({FooEvent.class, BarEvent.class})
public void handleFooBar() { .... }

Issue: SPR-13156
This commit is contained in:
Stephane Nicoll
2015-07-08 14:51:07 +02:00
parent ef0eb01f93
commit bf786c3176
7 changed files with 268 additions and 33 deletions

View File

@@ -22,6 +22,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.event.ApplicationListenerMethodAdapter;
import org.springframework.core.ResolvableType;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
@@ -36,7 +39,7 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
@Test
public void noAnnotation() {
Method m = ReflectionUtils.findMethod(PhaseConfigurationTestListener.class,
Method m = ReflectionUtils.findMethod(SampleEvents.class,
"noAnnotation", String.class);
thrown.expect(IllegalStateException.class);
@@ -46,24 +49,54 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
@Test
public void defaultPhase() {
Method m = ReflectionUtils.findMethod(PhaseConfigurationTestListener.class, "defaultPhase", String.class);
Method m = ReflectionUtils.findMethod(SampleEvents.class, "defaultPhase", String.class);
assertPhase(m, TransactionPhase.AFTER_COMMIT);
}
@Test
public void phaseSet() {
Method m = ReflectionUtils.findMethod(PhaseConfigurationTestListener.class, "phaseSet", String.class);
Method m = ReflectionUtils.findMethod(SampleEvents.class, "phaseSet", String.class);
assertPhase(m, TransactionPhase.AFTER_ROLLBACK);
}
@Test
public void phaseAndClassesSet() {
Method m = ReflectionUtils.findMethod(SampleEvents.class, "phaseAndClassesSet");
assertPhase(m, TransactionPhase.AFTER_COMPLETION);
supportsEventType(true, m, createGenericEventType(String.class));
supportsEventType(true, m, createGenericEventType(Integer.class));
supportsEventType(false, m, createGenericEventType(Double.class));
}
@Test
public void valueSet() {
Method m = ReflectionUtils.findMethod(SampleEvents.class, "valueSet");
assertPhase(m, TransactionPhase.AFTER_COMMIT);
supportsEventType(true, m, createGenericEventType(String.class));
supportsEventType(false, m, createGenericEventType(Double.class));
}
private void assertPhase(Method method, TransactionPhase expected) {
assertNotNull("Method must not be null", method);
TransactionalEventListener annotation = ApplicationListenerMethodTransactionalAdapter.findAnnotation(method);
assertEquals("Wrong phase for '" + method + "'", expected, annotation.phase());
}
private void supportsEventType(boolean match, Method method, ResolvableType eventType) {
ApplicationListenerMethodAdapter adapter = createTestInstance(method);
assertEquals("Wrong match for event '" + eventType + "' on " + method,
match, adapter.supportsEventType(eventType));
}
static class PhaseConfigurationTestListener {
private ApplicationListenerMethodTransactionalAdapter createTestInstance(Method m) {
return new ApplicationListenerMethodTransactionalAdapter("test", SampleEvents.class, m);
}
private ResolvableType createGenericEventType(Class<?> payloadType) {
return ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, payloadType);
}
static class SampleEvents {
public void noAnnotation(String data) {
}
@@ -76,6 +109,15 @@ public class ApplicationListenerMethodTransactionalAdapterTests {
public void phaseSet(String data) {
}
@TransactionalEventListener(classes = {String.class, Integer.class},
phase = TransactionPhase.AFTER_COMPLETION)
public void phaseAndClassesSet() {
}
@TransactionalEventListener(String.class)
public void valueSet() {
}
}
}