The following is perfectly legal code in Java 1.4.2. In fact, this is code that has existed in lab exercises for an Advanced Java Programming class I’ve taught for years.


    public void add(String item) {
        DefaultListModel model = (DefaultListModel) getModel();
        int count = model.getSize();
        int i = 0;
        while (i < count) {
            if (item.compareTo(model.get(i)) < 0) {
                break;
            }
            ++i;
        }
        model.add(i, item);
    }

So what’s wrong with it? Nothing! Except that it won’t compile in Java 5. But Java 5 is backwards compatible, right? NOT!

Here’s the problem. Look at this expression:

    item.compareTo(model.get(i))

The item object is a String, and its compareTo method is invoked with an Object argument (the return value of the DefaultListModel get(int) method). This is perfectly legal in Java 2 — the contract for Comparable.compareTo says that if the argument is of a type that cannot be compared, the implementation of compareTo should raise a ClassCastException. This continues to be the case in Java 5. In the code above that will never happen because only String objects are contained in the DefaultListModel object.

The failure to compile with Java 5 is a result of the way generics works. In Java 5, the interface for Comparable changes the compareTo signature from

    interface Comparable {
        int compareTo(Object o);
    }

to

    interface Comparable<T> {
        int compareTo(T o)
    }

where T is a parameterized generic type, instead of simply Object as before. The String class in Java 5 no longer implements Comparable, it implements Comparable<String>. There is no compareTo(Object) method because it has been removed from String, leaving only compareTo(String) (as it alone now satisfies the Comparable interface). Since the compareTo(Object) method is gone, my previously legal Java 2 code no longer compiles. I have to fix it by adding an explicit cast (I’m not supposed to have to do that):


    public void add(String item) {
        DefaultListModel model = (DefaultListModel) getModel();
        int count = model.getSize();
        int i = 0;
        while (i < count) {
            if (item.compareTo((String)model.get(i)) < 0) {
                break;
            }
            ++i;
        }
        model.add(i, item);
    }

And I thought Java Generics smelled on the outside!



No Responses to “Java 5 broke my Java 2 code”  

  1. No Comments

Leave a Reply