Updated: 3/5/2003; 11:07:39 AM.
Brian Maso's Tecno-Geek Weblog
The musings of a mild-mannered tecno-geek.
        

Monday, February 24, 2003

Event object classes in the Swing event hierarchy have something of a design flaw, in that they use subclassing merely for member inheritance, but without regard to reference type polymorphism.

For example, the ComponentListener interface defines four notification callback methods that receive ComponentEvent instances: componentHidden(), componentMoved(), componentResized() and componentShown(). However, these notification methods are designed so that only ComponentEvents will be delivered to them; ComponentEvent subclass instances are not supposed to be delivered by convention. The listener interface basically treats the event object class as if it were final. The ComponentEvent class is a supeclass for multiple different Swing event types: ContainerEvent, FocusEvent, InputEvent (which has subclasses KeyEvent and MouseEvent, which have further subclasses), PaintEvent and WindowEvent. All these subclass types of course inherit all the member type definitions defined in ComponentEvent. But the Swing framework assumes these subclasses will not be used where a ComponentEvent is expected.

Figure 1 is a class diagram showing the relationships between some of the AWT/Swing event object classes and listener interfaces.

This is a case of using inhertance to duplicate members, but which ignores type polymorphism. This system introduces runtime type ambiguity. For example, a MouseEvent could be delivered to any of the ComponentListener interface methods -- what would the meaning of this be? Clearly its some kind of mistake, but the problem would not be caught either by the runtime compiler, nor the Java runtime, and could cause strange side-effects in an application program.

With AWT/Swing event classes and instances we can see another aspect of the problem by looking at the getTypeID() method that's a member of all AWTEvent-derived classes. For any particular class, instances are supposed to return one of a few finite values from this method. The ComponentEvent class defines 4 constant int values: COMPONENT_MOVED, COMPONENT_RESIZED, COMPONENT_SHOWN and COMPONENT_HIDDEN. But in fact most ComponentEvent objects use completely different type ID constants. For example a MouseEvent, which is a COmponentEvent (i.e. "IS A" ComponentEvent) will not have one of these 4 type IDs. What happens when a ComponentListener receives a ComponentEvent whose type ID value is not one of the 4 proscribed ID values? Maybe nothing, or maybe a wierd side-effect.

In general this is going to be a problem when using a similar mechanism to model category/instance relationships (as opposed to modeling sub- and super-set and set membership relationships). That is, when using classes to model categories and object instances to model members of those categories. Category membership is exclusive: a member of a parent category is not a member of an sub-category. Object instances and their respective classes do not share this relationship, and so make a poor model.

We can design a framework for modeling categories and membership that would avoid the ambiguity problems, but otherwise would have the same features of the AWT/Swing event hierarchy design. This class hierarchy framework is characterized by a "backbone" of abstract base classes and concrete, final "leaf" classes representing categories. The listener interfaces would reference only the "leaf" classes, which would effectively remove the type ambiguity problems.

In this system, the AWTEvent base class would be directly extended by a set of abstract classes intended for extension. These would be the "backbone" classes in the class hierarchy. Each "backbone" class could be extended by concrete "leaf" classes, which would be referenced by the listener interfaces.

Figure 2 is a translation of the classes and interfaces in Figure 1, applying the "backbone" of abstract classes idea to better model event categories.


4:25:11 PM    comment []

Last week sparked some discussions on the Advanced-Java list at DM all about class loading. It all started when Robert Paris (no link?) wondered how he could achieve version-based class loading in Java. In a round-about way, this had me wondering exactly why you can't cast between different class revisions within a single VM. If the non-private class signatures are the same, then why not? This would be kind of the compliment to serializing across class loader boundaries. Instead of creating a new object from another's state (serialization), you'd be converting a reference type for the same object. I think it would prevent a lot of class loading problems that occur in RMI, Jini and other situations where you are communicating across class loader boundaries. Many other good thoughts from some very intelligent people. Check out the thread.


11:23:21 AM    comment []

© Copyright 2003 Brian Maso.
 
February 2003
Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28  
Jan   Mar


Click here to visit the Radio UserLand website.

Subscribe to "Brian Maso's Tecno-Geek Weblog" in Radio UserLand.

Click to see the XML version of this web page.

Click here to send an email to the editor of this weblog.