Search code examples
javajtreecomparatortreenodecompareto

comparing two TreeNode (or DefaultMutableTreeNode) objects in Java Comparator


My goal is very simple today, I am trying to work out the proper way to implement compareTo (or the Comparable) interface for my class which extends DefaultMutableTreeNode.

The problem is this: Say I have a perfectly good class that represents times. I've already written a perfectly good compareTo method (which works as I desire) that I've tested out with Arrays.sort() with marvelous results.

Now lets say I have a JTree with bunches of different objects, like this:

    new SpecialNode("Zomg a string!"); // add this group of nodes right here
    new SpecialNode(new Time("8:55 PM"));
    new SpecialNode(new SomeTypeYouveNeverHeardOf());

So, being a professional programmer, I immediately start coding without any forethought whatsoever. Here is my SpecialNode class:

class SpecialNode extends DefaultMutableTreeNode implements Comparator<SpecialNode>
{
    public int compareTo(SpecialNode sn)
    {
        // Not only does this not work correctly (read: at all)
        // But, it is sub-par, how do I get the type information out of the userObject
        // So I can cast it correctly and call the correct compareTo method!!
        return this.getUserObject().toString().compareTo(sn.getUserObject().toString());
    }
}

Ok, so if you didn't read the comments (which, admit, you didn't); My problem is that within the compareTo method of SpecialNode, I only have access to the userObject. Sadly, I do not know what the userObject used to be, and as such, I cannot properly cast it to call the correct compareTo method!

This is really a pain, since I've already written several perfectly good compareTo methods in all of the classes which will be added to my tree. So can someone help a guy out and drop me a hint?

tl;dr - How do I get type information out of an generic object that DefaultMutableTreeNode stores? If that is not possible, how should I go about comparing two instances of SpecialNode when I don't even know what they may contain!

Thanks in advance.


Solution

  • I'm assuming you can't have a TreeNode for each type of data. Does it make sense in your use case to do comparisons if the type is different?

    Ideas:

    1. Can SimpleNode know all of the possible types and do instanceof and casts to the correct type for Comparable? This is the way I would have handled it a few years ago.

    2. How do you feel about unchecked warnings? I had a similar problem before using a JList and couldn't quite make the compiler happy (I gave up the swing default model to make my life easier). Maybe someone else could improve on this answer?

      class SpecialNode<T extends Comparable<T>> extends DefaultMutableTreeNode 
                                                implements Comparable<SpecialNode>
      {
        T typedUserObject;
        SpecialNode(T t)
        {
           this.typedUserObject = t;
           setUserObject(t);
        }
      
      
        public int compareTo(SpecialNode node)
        {
            if(typedUserObject.getClass().isInstance(node.typedUserObject))
            {
                T otherObj = (T) node.typedUserObject;
                return typedUserObject.compareTo(otherObj);
            }
            else
            {
                //What are you going to do if they're not the same type?
                return -1;
            }
        }
      
      
      }
      

    Edit: If you know they should be the same type - eliminates check

    class SpecialNode<T extends Comparable<T>> extends DefaultMutableTreeNode
                                              implements Comparable<SpecialNode<T>>
    {
      T typedUserObject;
      SpecialNode(T t)
      {
         this.typedUserObject = t;
         setUserObject(t);
      }
    
    
      public int compareTo(SpecialNode<T> node)
      {
         return typedUserObject.compareTo(node.typedUserObject);
      }    
    }
    

    If you don't want the code in the node itself (I don't think I would), you might create a separate class that implements Comparator<SpecialNode<T>>