提交 b0ff834e 编写于 作者: P Phillip Webb

Multicaster support for events with null source

Update `AbstractApplicationEventMulticaster` to support `EventObjects`
with a null source (which can happen if they have been serialized).

Issue: SPR-10945
上级 6d882b14
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.OrderComparator;
import org.springframework.util.ObjectUtils;
/**
* Abstract implementation of the {@link ApplicationEventMulticaster} interface,
......@@ -134,7 +135,8 @@ public abstract class AbstractApplicationEventMulticaster implements Application
*/
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
Class<? extends ApplicationEvent> eventType = event.getClass();
Class sourceType = event.getSource().getClass();
Object source = event.getSource();
Class sourceType = (source == null ? null : source.getClass());
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
......@@ -212,12 +214,14 @@ public abstract class AbstractApplicationEventMulticaster implements Application
return true;
}
ListenerCacheKey otherKey = (ListenerCacheKey) other;
return (this.eventType.equals(otherKey.eventType) && this.sourceType.equals(otherKey.sourceType));
return ObjectUtils.nullSafeEquals(this.eventType, otherKey.eventType)
&& ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType);
}
@Override
public int hashCode() {
return this.eventType.hashCode() * 29 + this.sourceType.hashCode();
return ObjectUtils.nullSafeHashCode(this.eventType) * 29
+ ObjectUtils.nullSafeHashCode(this.sourceType);
}
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -77,7 +77,7 @@ public class SourceFilteringListener implements SmartApplicationListener {
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType.isInstance(this.source);
return (sourceType != null && sourceType.isInstance(this.source));
}
@Override
......
......@@ -16,8 +16,13 @@
package org.springframework.context;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Locale;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.AbstractListableBeanFactoryTests;
import org.springframework.tests.sample.beans.LifecycleBean;
......@@ -129,11 +134,29 @@ public abstract class AbstractApplicationContextTests extends AbstractListableBe
}
public void testEvents() throws Exception {
doTestEvents(this.listener, this.parentListener, new MyEvent(this));
}
@Test
public void testEventsWithNoSource() throws Exception {
// See SPR-10945 Serialized events result in a null source
MyEvent event = new MyEvent(this);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(event);
oos.close();
event = (MyEvent) new ObjectInputStream(new ByteArrayInputStream(
bos.toByteArray())).readObject();
doTestEvents(this.listener, this.parentListener, event);
}
protected void doTestEvents(TestListener listener, TestListener parentListener,
MyEvent event) {
listener.zeroCounter();
parentListener.zeroCounter();
assertTrue("0 events before publication", listener.getEventCount() == 0);
assertTrue("0 parent events before publication", parentListener.getEventCount() == 0);
this.applicationContext.publishEvent(new MyEvent(this));
this.applicationContext.publishEvent(event);
assertTrue("1 events after publication, not " + listener.getEventCount(), listener.getEventCount() == 1);
assertTrue("1 parent events after publication", parentListener.getEventCount() == 1);
}
......
......@@ -45,19 +45,13 @@ public abstract class AbstractXmlWebApplicationContextTests extends AbstractAppl
* @see org.springframework.context.AbstractApplicationContextTests#testEvents()
*/
@Override
public void testEvents() throws Exception {
TestListener listener = (TestListener) this.applicationContext.getBean("testListener");
listener.zeroCounter();
TestListener parentListener = (TestListener) this.applicationContext.getParent().getBean("parentListener");
parentListener.zeroCounter();
parentListener.zeroCounter();
assertTrue("0 events before publication", listener.getEventCount() == 0);
assertTrue("0 parent events before publication", parentListener.getEventCount() == 0);
this.applicationContext.publishEvent(new MyEvent(this));
assertTrue("1 events after publication, not " + listener.getEventCount(), listener.getEventCount() == 1);
assertTrue("1 parent events after publication", parentListener.getEventCount() == 1);
}
protected void doTestEvents(TestListener listener, TestListener parentListener,
MyEvent event) {
TestListener listenerBean = (TestListener) this.applicationContext.getBean("testListener");
TestListener parentListenerBean = (TestListener) this.applicationContext.getParent().getBean("parentListener");
super.doTestEvents(listenerBean, parentListenerBean, event);
};
@Override
public void testCount() {
......
......@@ -96,18 +96,11 @@ public class XmlWebApplicationContextTests extends AbstractApplicationContextTes
* @see org.springframework.context.AbstractApplicationContextTests#testEvents()
*/
@Override
public void testEvents() throws Exception {
TestListener listener = (TestListener) this.applicationContext.getBean("testListener");
listener.zeroCounter();
TestListener parentListener = (TestListener) this.applicationContext.getParent().getBean("parentListener");
parentListener.zeroCounter();
parentListener.zeroCounter();
assertTrue("0 events before publication", listener.getEventCount() == 0);
assertTrue("0 parent events before publication", parentListener.getEventCount() == 0);
this.applicationContext.publishEvent(new MyEvent(this));
assertTrue("1 events after publication, not " + listener.getEventCount(), listener.getEventCount() == 1);
assertTrue("1 parent events after publication", parentListener.getEventCount() == 1);
protected void doTestEvents(TestListener listener, TestListener parentListener,
MyEvent event) {
TestListener listenerBean = (TestListener) this.applicationContext.getBean("testListener");
TestListener parentListenerBean = (TestListener) this.applicationContext.getParent().getBean("parentListener");
super.doTestEvents(listenerBean, parentListenerBean, event);
}
@Override
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册