A WHILE AGO
- By Robb Shecter
- December 15, 1999
I had a problem with a program I was writing. I was working on a
dialog for a simple database application with contact information. The dialog was to
display a List
of names from the database, and when a
user clicked on one of the names, detailed information about the person would be shown.
I was using the AWT List
class, and the more I thought
about the problem, the harder it got. When an item got selected, the List
class would report the first and last name of the person. In that case, my program would not receive
the unique ID of the person—and to retrieve it, I'd have to somehow parse out the user's name
and do a query. In order to make the parsing and query easier, I might have to display the names
in the List
," instead of the way I had originally wanted the user to see
them: "FirstName LastName
." And, what would happen if two
users had the same name? The quick solution that first came to mind was to maintain a parallel
or Person ID
numbers. The program would add a
object to this Vector every time it put his/her name in
. Then, when a name was selected, I could fish out the
real information from the Vector. But this would get messy fast. I would have to make sure that every
piece of code that made changes to the List
would also make changes
to this parallel Vector
. I also didn't like this solution because I'd
seen the results of similar hacks done in very un-object-oriented (OO) C programming.
The true problem was that although the Java class libraries are OO, they only partially support OO
programming. The AWT List
only works with strings, so it's difficult to use it to view and select objects. The
class can also be difficult to use. The information
you want to display has to be somehow put into a TableModel
then plugged into a JTable
. Programming in a truly OO style may
mean implementing several different TableModels
that extract the
information you want to show. Put another way, the problem is similar to the "impedance mismatch" that
occurs when relational databases are used with OO systems; only part of a program works easily and
natively with objects, forcing them to be "flattened out" into scalar values, and then later "unflattened"
back into true objects.
After realizing what my real problem was, I considered how I'd like to use widgets and objects. Here's
what I came up with: It would be cool if I could take a bunch of objects and throw them to a widget,
which would then display them in the best way it could. The widget would let the user select one or
more of the objects. If the program asked the widget for the thing that got selected, it would get
a reference to a real object, not just a description of it. An advanced widget would even let the
user manipulate or edit the objects in some way.
I solved several user interface (UI) problems by extending an AWT and a Swing widget to make them act
more OO. The work I describe here can easily be applied to other UI classes.
Extending the AWT List
The AWT List
class has the following methods (among others) for
adding and retrieving strings:
The AWT List
class would be much more usable if it had a method
like addObject(Object, String)
, which would add the given object
to its List
and represent it with the given
. It could also have a method
as a convenience that would call
to obtain the String representation.
Finally, it would have getSelectedObject()
, parallel to
the original getSelectedItem()
Implementing this was fairly easy: I just applied "standard" OO refactoring to my original hack.
If I had kept on using the "parallel Vector
" idea, I would have
ended up with lots of applications, all using instances of List
and all maintaining their own parallel Vectors
. My solution was
to have a special List
class that maintains its own parallel
internally, eliminating redundant coding. The
would be private, and manipulated when a public method
is called. Subclassing the List
class was the best way to implement
this. My new OOList
class would support the full
API, allowing it to be used in IDEs or programs where the
is. My new class would simply be a set of wrappers
around the original methods, all very similar to this:
public synchronized void removeAll() (
Besides creating an OO interface and eliminating redundancy, this code is much safer. The
is guaranteed not to get out of sync
with the List
because clients can access it only through
the public methods. This achieves a key goal of OO design: An object should guarantee the
integrity of its own data. Listings 1
show two simple classes that
represent typical domain objects. OOListTest.java
uses them to demonstrate
how the new OOList
class can be used. Figure 1 shows the results.
Figure 1. OOList
Extending the Swing JTable
Swing brought many improvements to Java. The JList
class, in fact,
allows any object type to be added to its list. This fixes the AWT List
String-only problem, when Swing can be used. There are still some areas of Swing, though, that can use
I soon found myself in a typical database programmer's situation: I was writing lots of applications where
I needed to display information from a database, let the users change some of it, and then store the
updates. I had already made an OO API for my data storage (which was relational), but making the UIs
was turning into a lot of work. The programs were designed for a biological laboratory. Typically, a
user would want to look at a set of 50 or so samples, each one having 10 properties such as temperature
or quantity. The user could then edit some of the properties and save the modified objects.
The Swing JTable
was the natural choice for displaying this data. The
easiest way to store information in a JTable
is to use the
, which accepts a two-dimensional array, or
doesn't recommend this approach, and sure enough, my needs were too complex for the simple
class. When I realized this, I started to
rewrite my code to use the JTable
as JavaSoft intended. I
made custom TableModel
implementations that get plugged into
. The easiest way to do this is to subclass
and implement the following methods:
- int getColumnCount()
- int getRowCount()
- Object getValueAt(int row, int col)
will then call these methods when it needs to. Optionally,
other methods can be overridden in order to let the JTable
table data, as well as display more detailed information. Here are some of the more interesting ones:
- boolean isCellEditable(int row, int col)
- void setValueAt(Object, int row, int col)
- String getColumnName(int index)
- Class getColumnClass(int index)
The table model would know about the particular properties of my domain objects, and let the
edit and view them. This worked better—my code was
cleaner, but I soon ran into another problem. Every dialog I was writing needed to show a different
set of objects, and for each type of object, I found myself making a new
It occurred to me that, once again, I was writing somewhat un-OO code in order to work with UI widgets:
I had classes that dissembled my objects into scalar values, and reassembled them again. It was turning
into a maintenance problem, because changing my domain classes (the actual classes I wanted to work with
") caused me to change the
that know how to work with them. I started thinking about how I'd like to use
s if I could. Instead of giving the
a two-dimensional array of scalar values, it would be better if I could give it a
one-dimensional array of the objects themselves. Objects would be displayed one per row; and the
columns would somehow automatically show the objects' properties. But how would this happen? I realized
that the JavaBean system would be perfect. The new development process would look something like this:
First, a special TableModel
, is implemented. This class accepts a one-dimensional array of objects in its
constructor. It analyzes the objects' class using the JavaBean
to get a List
of the class' PropertyDescriptors
has information about a single JavaBean
- A "display name" for the property.
- A "read method" that gives access to the property.
- Possibly a "write method" that sets a new value for the property.
Here's how the basic TableModel
interface is implemented:
- getRowCount()—Return the length of the object array.
- getColumnCount()—Return the length of property List.
- getColumnName(i)—Return the display name of property[i].
- getValueAt(row, col)—Get the read method of property[col], and execute it on object[row].
- setValueAt(object, row, col)—Similar to above, but get and execute the property's write method if there is one.
Finally, this last method gives a JTable
information about whether a
user should be allowed to edit a column:
- isEditable(col)—Get property[i], and return true if it has a write method.
Once the OOTableModel
was completed, I needed to make sure that
my domain classes adhered to the JavaBean standard. This isn't hard to do: For any
, a class should provide access to it via
methods named getAbc
it's writable. Alternatively, Beaninfo
classes can be generated or
written that give detailed information to the Introspector
the previous example are basic JavaBeans. Animal has three writable
and adds a read-only property,
Figure 2. OOLTable
Finally, using the new classes is very easy. Listing 4 00JTableTest.java
, gives an example. Figure 2 shows the results. Whenever I have a List
of objects that I want to show the user, I instantiate a new OOTableModel
with the object List
, pass it to a JTable
, and display it. The JTable
automatically displays the objects one per line, and their properties one per column. The user can click on the cells and change the values. Properties that don't have a set method will be read-only and the JTable
won't let the user edit them. It's a bit difficult to see in a screenshot, but the Dog's "ageInDogYears"
property is read-only and no edit field appears when the user clicks on it. I also made a subclass of JTable
as a convenience to save myself the step of separately instantiating the table model.
enhancement described so far is just the beginning of what
can be done. One issue that isn't resolved yet is what happens if the objects change while they're being
displayed. The TableModel
classes have a nice notification protocol that's easy to use when subclassing AbstractTableModel
like I have. The AbstractTableModel
has several methods for telling a JTable
that something has changed, such as:
can then query the
for the new values and repaint the changed cells. Figure 3 shows the sequence of
notification actions. A domain object lets the TableModel
that it has changed.
Figure 3. Notification.
Another part of the JavaBean specification describes "bound properties." A JavaBean automatically
eners whenever any of these properties are changed.
Using bound properties is like using the Observer/Observable
classes, except bound properties are more flexible because the Observable
object isn't required to subclass a particular class. Instead, the PropertyChangeSupport
class takes care of most of the work involved. Listing 5
, and Listing 6
, show the modified JavaBeans, which now have bound properties. All that remained was to change OOTableModel
in two ways. First, it must try to register itself as a property listener of each object it receives. I did this by using reflection and ignoring any exceptions that are thrown. The TableModel
must also be modified to react correctly when it's notified about a change. Its implementation of the propertyChange(PropertyChangeEvent)
method acts like a relay, catching the property change notifications and, in turn, sending out notifications about TableModel changes
With these additions, a JTable
will automatically repaint itself
when the data changes.
Benefits of OO Widgets
I discovered that being able to directly display real objects in UI widgets encourages better and more
- References to many kinds of objects can be passed to the OOTableModel, including persistent database objects, domain objects, report objects, and remote RMI objects. Objects that are cast as abstract classes or interfaces can also be used.
- The system uses standard JavaBean features, which means that most classes don't have to be modified to work with the OOTableModel. Third-party classes can be used without modification or access to their source code.
- The need to spread information about domain objects throughout programs is reduced. Normally, a UI class must know something about the classes it displays. This introduces redundancy, which is a maintenance problem. With OO widgets, objects can be conveniently described just once where they should be—in the class source code. The system then reuses this description at runtime.
- OO design and polymorphism can be used to create interesting effects such as database-like "views" onto the objects. Note the difference between the "Animals" table and the "Dogs" table in Figure 2.
- OOTableModel and OOJTable are consistent with Swing design and can be combined with other Swing features like cell renderers.
The most obvious use for these new widgets is in easy-to-construct dialogs. Very little extra coding needs
to be done aside from checking whether an "OK
" button was clicked. The application can then proceed using
the objects like it normally would. Moving beyond this, the notification/update feature has some interesting
possibilities. A small system to monitor the state of a running program could be made. Some key objects in
the system would be passed to OO widgets, where a user could observe changes that occur in them over the
lifetime of the program.
All object references are considered equal and a remote reference can be displayed just as easily. This
feature could be used in a distributed application control system. For example, a collection of references
to remote servers could be passed to an OOJTable
, allowing an
administrator to view their status, shut them down, and start them up.
Ideas for the Future
A neat feature of the model-view design is that the pieces can be separated and used in other contexts.
doesn't have to be used with a
. Having table-like access to a set of objects and their
properties can be helpful in other settings. For example, I've been playing with classes that use a
to generate HTML in servlets. Coupling these with the
has made it easy to quickly write Web applications.
Taking this further, these HTML producing classes could create a layer between DHTML or HTTP that would
change browser events into sets and gets to a TableModel
An object browser could be created by extending the OO widget idea. For example, maybe clicking the right
mouse button over a cell in a JTable
would cause that object to be
"inspected" in a new window. All of its properties would then be displayed and could be edited. These
properties could then themselves be inspected, etc.
class could be easily modified to accept a
its constructor. This would make it easier to use in typical applications. In these cases, though,
there wouldn't be any guarantees that all objects would be the same type, or could be displayed.
Changes in objects can be detected with the notification enhancements I describe. However, changes to the
List of objects itself are not accounted for. This might be a handy feature: detecting additions and
deletions from the List of objects, and notifying Listeners about them.
Finally, it would be interesting to enhance other Swing model interfaces. As I mentioned in the HTML
example, a TableModel
is a useful tool for abstraction apart from
Swing. Having easy-to-use extensions added to the other Swing interfaces could enable new types of flexible
applications to be built around them.