Skip to content

Commit 478d725

Browse files
committed
GenericApplicationListenerAdapter caches resolved event types
Issue: SPR-16970
1 parent 52d124d commit 478d725

File tree

4 files changed

+32
-22
lines changed

4 files changed

+32
-22
lines changed

spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -16,13 +16,16 @@
1616

1717
package org.springframework.context.event;
1818

19+
import java.util.Map;
20+
1921
import org.springframework.aop.support.AopUtils;
2022
import org.springframework.context.ApplicationEvent;
2123
import org.springframework.context.ApplicationListener;
2224
import org.springframework.core.Ordered;
2325
import org.springframework.core.ResolvableType;
2426
import org.springframework.lang.Nullable;
2527
import org.springframework.util.Assert;
28+
import org.springframework.util.ConcurrentReferenceHashMap;
2629

2730
/**
2831
* {@link GenericApplicationListener} adapter that determines supported event types
@@ -35,6 +38,9 @@
3538
*/
3639
public class GenericApplicationListenerAdapter implements GenericApplicationListener, SmartApplicationListener {
3740

41+
private static final Map<Class<?>, ResolvableType> eventTypeCache = new ConcurrentReferenceHashMap<>();
42+
43+
3844
private final ApplicationListener<ApplicationEvent> delegate;
3945

4046
@Nullable
@@ -86,17 +92,11 @@ public int getOrder() {
8692
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
8793
}
8894

89-
@Nullable
90-
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
91-
ResolvableType resolvableType = ResolvableType.forClass(listenerType).as(ApplicationListener.class);
92-
return (resolvableType.hasGenerics() ? resolvableType.getGeneric() : null);
93-
}
9495

9596
@Nullable
9697
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
9798
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
98-
if (declaredEventType == null || declaredEventType.isAssignableFrom(
99-
ResolvableType.forClass(ApplicationEvent.class))) {
99+
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
100100
Class<?> targetClass = AopUtils.getTargetClass(listener);
101101
if (targetClass != listener.getClass()) {
102102
declaredEventType = resolveDeclaredEventType(targetClass);
@@ -105,4 +105,14 @@ private static ResolvableType resolveDeclaredEventType(ApplicationListener<Appli
105105
return declaredEventType;
106106
}
107107

108+
@Nullable
109+
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
110+
ResolvableType eventType = eventTypeCache.get(listenerType);
111+
if (eventType == null) {
112+
eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
113+
eventTypeCache.put(listenerType, eventType);
114+
}
115+
return (eventType != ResolvableType.NONE ? eventType : null);
116+
}
117+
108118
}

spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -33,13 +33,13 @@ protected ResolvableType getGenericApplicationEventType(String fieldName) {
3333
try {
3434
return ResolvableType.forField(TestEvents.class.getField(fieldName));
3535
}
36-
catch (NoSuchFieldException e) {
36+
catch (NoSuchFieldException ex) {
3737
throw new IllegalStateException("No such field on Events '" + fieldName + "'");
3838
}
3939
}
4040

41-
protected static class GenericTestEvent<T>
42-
extends ApplicationEvent {
41+
42+
protected static class GenericTestEvent<T> extends ApplicationEvent {
4343

4444
private final T payload;
4545

@@ -51,11 +51,9 @@ public GenericTestEvent(Object source, T payload) {
5151
public T getPayload() {
5252
return this.payload;
5353
}
54-
5554
}
5655

57-
protected static class SmartGenericTestEvent<T>
58-
extends GenericTestEvent<T> implements ResolvableTypeProvider {
56+
protected static class SmartGenericTestEvent<T> extends GenericTestEvent<T> implements ResolvableTypeProvider {
5957

6058
private final ResolvableType resolvableType;
6159

@@ -119,6 +117,7 @@ public void onApplicationEvent(GenericTestEvent<String> event) {
119117

120118
@SuppressWarnings("rawtypes")
121119
static class RawApplicationListener implements ApplicationListener {
120+
122121
@Override
123122
public void onApplicationEvent(ApplicationEvent event) {
124123
}
@@ -137,7 +136,6 @@ static class TestEvents {
137136
public GenericTestEvent<IllegalStateException> illegalStateExceptionEvent;
138137

139138
public GenericTestEvent<IOException> ioExceptionEvent;
140-
141139
}
142140

143141
}

spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
6363

6464
@Test
6565
public void multicastSimpleEvent() {
66+
multicastEvent(true, ApplicationListener.class,
67+
new ContextRefreshedEvent(new StaticApplicationContext()), null);
6668
multicastEvent(true, ApplicationListener.class,
6769
new ContextClosedEvent(new StaticApplicationContext()), null);
6870
}

spring-context/src/test/java/org/springframework/context/event/GenericApplicationListenerAdapterTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -100,8 +100,7 @@ public void genericListenerStrictTypeNotMatchTypeErasure() {
100100

101101
@Test
102102
public void genericListenerStrictTypeSubClass() {
103-
supportsEventType(false, ObjectEventListener.class,
104-
getGenericApplicationEventType("longEvent"));
103+
supportsEventType(false, ObjectEventListener.class, getGenericApplicationEventType("longEvent"));
105104
}
106105

107106
@Test
@@ -111,7 +110,7 @@ public void genericListenerUpperBoundType() {
111110
}
112111

113112
@Test
114-
public void genericListenerUpperBoundTypeNotMatching() throws NoSuchFieldException {
113+
public void genericListenerUpperBoundTypeNotMatching() {
115114
supportsEventType(false, UpperBoundEventListener.class,
116115
getGenericApplicationEventType("ioExceptionEvent"));
117116
}
@@ -142,8 +141,9 @@ public void genericListenerRawTypeTypeErasure() {
142141
supportsEventType(true, RawApplicationListener.class, eventType);
143142
}
144143

145-
private void supportsEventType(boolean match, Class<? extends ApplicationListener> listenerType,
146-
ResolvableType eventType) {
144+
145+
private void supportsEventType(
146+
boolean match, Class<? extends ApplicationListener> listenerType, ResolvableType eventType) {
147147

148148
ApplicationListener<?> listener = mock(listenerType);
149149
GenericApplicationListenerAdapter adapter = new GenericApplicationListenerAdapter(listener);

0 commit comments

Comments
 (0)