public void fireEvent(EventObject event) {
// It is not necessary to send any events if there are no listeners
if (listenerList != null) {
+
+ // Make a copy of the listener list to allow listeners to be added
+ // inside listener methods. Fixes #3605.
+
// Send the event to all listeners. The listeners themselves
// will filter out unwanted events.
-
- final Iterator i = listenerList.iterator();
- while (i.hasNext()) {
- ((ListenerMethod) i.next()).receiveEvent(event);
+ final Object[] listeners = listenerList.toArray();
+ for (int i = 0; i < listeners.length; i++) {
+ ((ListenerMethod) listeners[i]).receiveEvent(event);
}
+
}
}
}
--- /dev/null
+package com.vaadin.tests.server;
+
+import junit.framework.TestCase;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.ui.TextField;
+
+public class TestEventRouter extends TestCase {
+
+ int innerListenerCalls = 0;
+
+ public void testAddInEventListener() {
+ final TextField tf = new TextField();
+
+ final ValueChangeListener outer = new ValueChangeListener() {
+
+ public void valueChange(ValueChangeEvent event) {
+ ValueChangeListener inner = new ValueChangeListener() {
+
+ public void valueChange(ValueChangeEvent event) {
+ innerListenerCalls++;
+ System.out.println("The inner listener was called");
+ }
+ };
+
+ tf.addListener(inner);
+ }
+ };
+
+ tf.addListener(outer);
+ tf.setValue("abc"); // No inner listener calls, adds one inner
+ tf.setValue("def"); // One inner listener call, adds one inner
+ tf.setValue("ghi"); // Two inner listener calls, adds one inner
+ assert (innerListenerCalls == 3);
+ }
+}