GenericApplicationListenerAdapter caches resolved event types
Issue: SPR-16970
This commit is contained in:
parent
52d124de6f
commit
478d7255d2
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.context.event;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
|
@ -23,6 +25,7 @@ import org.springframework.core.Ordered;
|
|||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
|
||||
/**
|
||||
* {@link GenericApplicationListener} adapter that determines supported event types
|
||||
|
|
@ -35,6 +38,9 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class GenericApplicationListenerAdapter implements GenericApplicationListener, SmartApplicationListener {
|
||||
|
||||
private static final Map<Class<?>, ResolvableType> eventTypeCache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
|
||||
private final ApplicationListener<ApplicationEvent> delegate;
|
||||
|
||||
@Nullable
|
||||
|
|
@ -86,17 +92,11 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
|
|||
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
|
||||
ResolvableType resolvableType = ResolvableType.forClass(listenerType).as(ApplicationListener.class);
|
||||
return (resolvableType.hasGenerics() ? resolvableType.getGeneric() : null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
|
||||
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
|
||||
if (declaredEventType == null || declaredEventType.isAssignableFrom(
|
||||
ResolvableType.forClass(ApplicationEvent.class))) {
|
||||
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
|
||||
Class<?> targetClass = AopUtils.getTargetClass(listener);
|
||||
if (targetClass != listener.getClass()) {
|
||||
declaredEventType = resolveDeclaredEventType(targetClass);
|
||||
|
|
@ -105,4 +105,14 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
|
|||
return declaredEventType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
|
||||
ResolvableType eventType = eventTypeCache.get(listenerType);
|
||||
if (eventType == null) {
|
||||
eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
|
||||
eventTypeCache.put(listenerType, eventType);
|
||||
}
|
||||
return (eventType != ResolvableType.NONE ? eventType : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -33,13 +33,13 @@ public abstract class AbstractApplicationEventListenerTests {
|
|||
try {
|
||||
return ResolvableType.forField(TestEvents.class.getField(fieldName));
|
||||
}
|
||||
catch (NoSuchFieldException e) {
|
||||
catch (NoSuchFieldException ex) {
|
||||
throw new IllegalStateException("No such field on Events '" + fieldName + "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected static class GenericTestEvent<T>
|
||||
extends ApplicationEvent {
|
||||
|
||||
protected static class GenericTestEvent<T> extends ApplicationEvent {
|
||||
|
||||
private final T payload;
|
||||
|
||||
|
|
@ -51,11 +51,9 @@ public abstract class AbstractApplicationEventListenerTests {
|
|||
public T getPayload() {
|
||||
return this.payload;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class SmartGenericTestEvent<T>
|
||||
extends GenericTestEvent<T> implements ResolvableTypeProvider {
|
||||
protected static class SmartGenericTestEvent<T> extends GenericTestEvent<T> implements ResolvableTypeProvider {
|
||||
|
||||
private final ResolvableType resolvableType;
|
||||
|
||||
|
|
@ -119,6 +117,7 @@ public abstract class AbstractApplicationEventListenerTests {
|
|||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static class RawApplicationListener implements ApplicationListener {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
}
|
||||
|
|
@ -137,7 +136,6 @@ public abstract class AbstractApplicationEventListenerTests {
|
|||
public GenericTestEvent<IllegalStateException> illegalStateExceptionEvent;
|
||||
|
||||
public GenericTestEvent<IOException> ioExceptionEvent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
|
|||
|
||||
@Test
|
||||
public void multicastSimpleEvent() {
|
||||
multicastEvent(true, ApplicationListener.class,
|
||||
new ContextRefreshedEvent(new StaticApplicationContext()), null);
|
||||
multicastEvent(true, ApplicationListener.class,
|
||||
new ContextClosedEvent(new StaticApplicationContext()), null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -100,8 +100,7 @@ public class GenericApplicationListenerAdapterTests extends AbstractApplicationE
|
|||
|
||||
@Test
|
||||
public void genericListenerStrictTypeSubClass() {
|
||||
supportsEventType(false, ObjectEventListener.class,
|
||||
getGenericApplicationEventType("longEvent"));
|
||||
supportsEventType(false, ObjectEventListener.class, getGenericApplicationEventType("longEvent"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -111,7 +110,7 @@ public class GenericApplicationListenerAdapterTests extends AbstractApplicationE
|
|||
}
|
||||
|
||||
@Test
|
||||
public void genericListenerUpperBoundTypeNotMatching() throws NoSuchFieldException {
|
||||
public void genericListenerUpperBoundTypeNotMatching() {
|
||||
supportsEventType(false, UpperBoundEventListener.class,
|
||||
getGenericApplicationEventType("ioExceptionEvent"));
|
||||
}
|
||||
|
|
@ -142,8 +141,9 @@ public class GenericApplicationListenerAdapterTests extends AbstractApplicationE
|
|||
supportsEventType(true, RawApplicationListener.class, eventType);
|
||||
}
|
||||
|
||||
private void supportsEventType(boolean match, Class<? extends ApplicationListener> listenerType,
|
||||
ResolvableType eventType) {
|
||||
|
||||
private void supportsEventType(
|
||||
boolean match, Class<? extends ApplicationListener> listenerType, ResolvableType eventType) {
|
||||
|
||||
ApplicationListener<?> listener = mock(listenerType);
|
||||
GenericApplicationListenerAdapter adapter = new GenericApplicationListenerAdapter(listener);
|
||||
|
|
|
|||
Loading…
Reference in New Issue