Collator.compare, DefaultRowSorter...

  • Thread starter softwarepearls_com
  • Start date
S

softwarepearls_com

In Collator, there's the following method:

public int compare(Object o1, Object o2) {
return compare((String)o1, (String)o2);
}

I would have thought that using toString() instead of a String cast
would be a bit more robust and flexible:

public int compare(Object o1, Object o2) {
return compare(o1.toString(), o2.toString());
}

As a result of the above, I'm currently seeing the following
ClassCastException when trying to sort a JTable column holding
Integers:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.lang.String
at java.text.Collator.compare(Collator.java:310)
at javax.swing.DefaultRowSorter.compare(DefaultRowSorter.java:951)
at javax.swing.DefaultRowSorter.access$100(DefaultRowSorter.java:95)
at javax.swing.DefaultRowSorter$Row.compareTo(DefaultRowSorter.java:
1359)
at javax.swing.DefaultRowSorter$Row.compareTo(DefaultRowSorter.java:
1349)
at java.util.Arrays.mergeSort(Arrays.java:1144)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.mergeSort(Arrays.java:1155)
at java.util.Arrays.sort(Arrays.java:1079)
at
javax.swing.DefaultRowSorter.sortExistingData(DefaultRowSorter.java:
536)
at javax.swing.DefaultRowSorter.setSortKeys(DefaultRowSorter.java:
304)
at javax.swing.DefaultRowSorter.toggleSortOrder(DefaultRowSorter.java:
463)
at javax.swing.plaf.basic.BasicTableHeaderUI
$MouseInputHandler.mouseClicked(BasicTableHeaderUI.java:93)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:
253)
at java.awt.Component.processMouseEvent(Component.java:6137)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5899)
at java.awt.Container.processEvent(Container.java:2023)
at java.awt.Component.dispatchEventImpl(Component.java:4501)
at java.awt.Container.dispatchEventImpl(Container.java:2081)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:
4301)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:
3974)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895)
at java.awt.Container.dispatchEventImpl(Container.java:2067)
at java.awt.Window.dispatchEventImpl(Window.java:2458)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:
269)
at
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:
184)
at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:
174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:
169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:
161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

(BTW: note the telltale signature in this trace of a recursive
method.. in this case Arrays.mergesort)

... Had Collator used the toString() approach, then this silly
exception could be avoided. It's just silly for Swing not to be able
to sort JTable rows on columns holding Integers.

Any ideas why Collator.compare has to be implemented using these
casts?
 
L

Lew

softwarepearls_com said:
In Collator, there's the following method:

public int compare(Object o1, Object o2) {
return compare((String)o1, (String)o2);
}

I would have thought that using toString() instead of a String cast
would be a bit more robust and flexible:

public int compare(Object o1, Object o2) {
return compare(o1.toString(), o2.toString());
}

As a result of the above, I'm currently seeing the following
ClassCastException when trying to sort a JTable column holding
Integers:

From the Javadocs for that method:
Throws: ClassCastException - the arguments cannot be cast to Strings.

So what else would you expect?

How does collating 'Integer' arguments even make sense?

Collation is inherently a string operation.
 
S

softwarepearls_com

 From the Javadocs for that method:


So what else would you expect?

It's just poor programming to have a method signature demanding Object
arguments, and logic which unconditionally casts, in this case to
String. That's just inviting the crash.
How does collating 'Integer' arguments even make sense?

Dunno.. DefaultRowSorter's author will know.
Collation is inherently a string operation.

Yep.. and what you just said is just enough to have led me to a copy-
paste bug in my code which is the root cause of the problem: I had
declared my JTable column to consist of Strings instead of Integers.
Thanks for the little push in the right direction!

It's a shame the various Swing renderers take Object as their value..
nowadays the design for renderers could be made much more robust with
a bit of generics. If my renderer had used generics, it would have
prevented the String vs Integer bug.
 
L

Lew

softwarepearls_com said:
It's just poor programming to have a method signature demanding Object
arguments, and logic which unconditionally casts, in this case to
String. That's just inviting the crash.

It's just poor programming to expect a method or class to behave differently
from how it's documented to behave.
 
T

Tom Anderson

.. Had Collator used the toString() approach, then this silly exception
could be avoided. It's just silly for Swing not to be able to sort
JTable rows on columns holding Integers.

Sorting a list of integers based on the collation sequence of their string
representation would be a really, really, stupid thing to do. Unless you
think this order:

1
10
2
3
4
5
6
7
8
9

is a good one?
Any ideas why Collator.compare has to be implemented using these
casts?

Collator orders strings. That's all it does. It has a method which takes
Object because it implements Comparable, which defines a compare method
which takes Object. Or at least, did in pre-generics days, and for some
reason, is now defined as a Comparator<Object> rather than a
Comparator<String>. Expecting it to handle non-String objects is just a
mistake - that's not its job.

However, you could well argue that this means it's poor design for
DefaultRowSorter to rely on Collator, since that means it will fail for
any non-string table contents. It could so easily define a
StringRepresentationCollator:

public class StringRepresentationCollator implements Comparator<Object> {
private Collator collator = Collator.getInstance() ;
public int compare(Object a, Object b) {
return collator.compare(a.toString(), b.toString()) ;
}
}

Or perhaps even:

public class SmartComparator implements Comparator<Object> {
private Collator collator = Collator.getInstance() ;
public int compare(Object a, Object b) {
if (a instanceof String) return collator.compare(a, b) ;
else if (a instanceof Comparable) return ((Comparable)a).compareTo(b) ;
else return collator.compare(a.toString(), b.toString()) ;
}
}

That would use collation order for strings, natural ordering for anything
else which has one, and collation order of string representations
otherwise.

Alternatively, since it's pretty trivial to set a comparator for a column,
you could just do that, and quit your whining!

tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top