private String describe(EventListener listener) {
   if (listener instanceof PropertyChangeListenerProxy) {
     PropertyChangeListenerProxy proxy = (PropertyChangeListenerProxy) listener;
     return proxy.getPropertyName() + " to " + describe(proxy.getListener());
   } else {
     return listener.toString();
   }
 }
  public void testAddingAListenerActuallyAddsAProxy() {
    Object bean = new Object();
    PropertyChangeSupport support = new PropertyChangeSupport(bean);
    PropertyChangeListener listener =
        new PropertyChangeListener() {
          public void propertyChange(PropertyChangeEvent event) {}
        };
    support.addPropertyChangeListener("a", listener);

    PropertyChangeListenerProxy p1 =
        (PropertyChangeListenerProxy) support.getPropertyChangeListeners()[0];
    assertEquals(PropertyChangeListenerProxy.class, p1.getClass());
    assertTrue(p1 != listener); // weird but consistent with the RI
    assertEquals("a", p1.getPropertyName());
    assertEquals(listener, p1.getListener());
  }
  public void testAddingAProxy() {
    Object bean = new Object();
    PropertyChangeSupport support = new PropertyChangeSupport(bean);
    PropertyChangeListener listener =
        new PropertyChangeListener() {
          public void propertyChange(PropertyChangeEvent event) {}
        };
    PropertyChangeListenerProxy proxy = new PropertyChangeListenerProxy("a", listener);
    support.addPropertyChangeListener("b", proxy);

    // this proxy sets us up to receive 'b' events
    PropertyChangeListenerProxy p1 =
        (PropertyChangeListenerProxy) support.getPropertyChangeListeners()[0];
    assertEquals(PropertyChangeListenerProxy.class, p1.getClass());
    assertEquals("b", p1.getPropertyName());

    // this proxy sets us up to receive 'a' events
    PropertyChangeListenerProxy p2 = (PropertyChangeListenerProxy) p1.getListener();
    assertEquals(PropertyChangeListenerProxy.class, p2.getClass());
    assertEquals("a", p2.getPropertyName());
    assertEquals(listener, p2.getListener());
  }