JDK-6184376 : Wrong generification of javax.swing.event.EventListenerList
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0,6
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic
  • CPU: generic
  • Submitted: 2004-10-26
  • Updated: 2017-05-19
  • Resolved: 2004-11-19
Related Reports
Duplicate :  
Relates :  
Description
I don't think the generification of javax.swing.event.EventListenerList is
correct:

$ javac -source 1.4 Test.java
$ javac -source 5 Test.java
Test.java:7: <T>add(java.lang.Class<T>,T) in javax.swing.event.EventListenerList cannot be applied to (java.lang.Class<capture of ? extends java.util.EventListener>,java.util.EventListener)
        list.add(l.getClass(), l);
            ^
1 error
$ cat -n Test.java
     1  import java.util.EventListener;
     2  import javax.swing.event.EventListenerList;
     3
     4  class Test {
     5      void test(EventListenerList list, EventListener l)
     6      {
     7          list.add(l.getClass(), l);
     8      }
     9  }

This is not a compiler bug.  The declaration of add should probably have been:

<T extends EventListener> void add(Class<? extends T> t, T l);

I think the remove method has the same problem.
###@###.### 10/26/04 05:21 GMT

Comments
EVALUATION While changing to: <T extends EventListener> void add(Class<? extends T> t, T l); Would fix this test case, the following would still be broken: ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent ae) { } }; list.add(al.getClass().getSuperclass(), al); Given this, I think the only way to make this backward compatable is to change the method to: void add(Class<?> t, EventListener l); ###@###.### 11/1/04 22:29 GMT Mark reminded me that this is documented and because this is not a common pattern a source incompatability is ok. I'm going to leave the bug open to see if more people bump into this, if not, I'll close out as we get closer to 1.6. ###@###.### 2004-11-05 19:38:42 GMT On further thinking about this, this test case isn't around how people use EventListenerList. The typical pattern for using EventListenerList is to have an addFoo method, something like: public void addActionListener(ActionListener l) { listenerList.add(ActionListener.class, l); } And when we extract the listeners we do: protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==ActionListener.class) { ... } } } So that the class passed to add is used as a key to later extract the listeners added for the particular type. If the code were instead: public void addActionListener(ActionListener l) { listenerList.add(l.getClass(), l); } We would effectively have a unique key for each class, and the code wouldn't work as expected. So, in thinking this through I don't think any customers have code like: void add(EventListenerList l, Foo f) { l.add(f.getClass(), f); } And even if they did, it wouldn't really work. Peter mentioned that there is still a problem with: public class TestGcd { public void myTest() throws ClassNotFoundException { Object lt = null; EventListenerList listenerList = new EventListenerList(); EventListener l = new UndoManager(); /* This gets error in JDK 1.5 */ listenerList.add( Class.forName((String)lt), l); /* but this is OK */ listenerList.add( (Class) Class.forName((String)lt), l); } Which is true, but again, I don't think any customers would do this. The typical use case is to pass in the class literal. Because neither of these are common cases, I'm closing this bug out as will not fix. ###@###.### 2004-11-19 18:55:18 GMT
01-11-2004