Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4075132
Votes 0
Synopsis Hashtable implementation makes extending hashtable dangerous
Category java:classes_util
Reported Against 1.1.2
Release Fixed
State 11-Closed, duplicate of 4089896, bug
Priority: 3-Medium
Related Bugs 4089896
Submit Date 28-AUG-1997
Description




The implementation of Hashtable.put() makes creating classes that
extend Hashtable and reimplement put and get very dangerous, in a
subtle and undocumented way.

Consider a class, say OrderedHashtable, that extends Hashtable 
and implements its own get and put methods.  OrderedHashtable 
wants to maintain the insertion order of entries in the table by
keeping a separate linked list of OrderedHashtableEntry objects,
each of which wraps an Object that was passed into its put() 
method.  The Objects stored in the underlying Hashtable are 
instances of OrderedHashtableEntry, not the origial objects that
were passed to OrderedHashtable.put

(One can argue about the merits of this implementation and 
suggest that the right relationship is OrderedHashtable HAS-A 
Hashtable, rather than IS-A Hashtable, but that's beside the 
point for now.)

Given the class described above, you get the following scenario
when the base Hashtable runs out of space:

(1) Client calls OrderedHashtable.put on some  customer  (O) of 
    type T, with some key (K) of type String.

(2) OrderedHashtable constructs a wrapper (W) of type 
    OrderedHashtableEntry around O and calls super.put(K, W) 
    to put it into the base hashtable.  This is usually okay 
    because OrderedHashtable.get will unwrap the value 
    for you and return O.

(3) If the hashtable is nearly full, Hashtable.put extends 
    the underlying data structure AND THEN RECURSIVELY CALLS 
    put() TO PUT THE OBJECT INTO THE NEW TABLE.

(4) The call to put resolves to OrderedHashtable.put instead 
    of to the normal Hashtable.put (because all non-final 
    methods in Java are virtual), which means 
    OrderedHashtable.put is now asked to use key K to store 
     customer  W instead of the original  customer  O.

(5) OrderedHashtable dutifully complies with this request, 
    wrapping the value in yet another instance of 
    OrderedHashtableEntry (W2) and storing that in
    the table under key K.

When you go to retrieve the value for K, OrderedHashtable 
retrieves W2 and then unwraps it, handing you back W, which 
is what it got from the recursive call to put that was made 
by the Hashtable internals in step (3), but which is NOT the 
 customer  you originally asked it to store.

Hashtable should not be calling put() recurisively after 
extending the table -- it should use a private method to actually
store data in the table so that subclasses can't get into this
broken state, or else it should extend the table and then store
the value inline in Hashtable.put


======================================================================
Work Around




A hastable subclass like OrderedHashtable can check in its own
put() method to see whether the value being stored is of type
OrderedHashtableEntry, and if so assume a recursive call from 
the superclass put method, but this is a truly ugly hack.
======================================================================
Evaluation
N/A
Comments
  
  Include a link with my name & email   

Submitted On 03-FEB-1999
Stendal
The internal use of public non-final methods can be really confusing sometimes.
In general, developer should know nothing about implementation of a class, but
it may be useful to make some note indicating that this method is used
internally and provide a list of methods which use it. Then, if a developer has
a problem with subclass (as I do), this note can give him a hint to inspect
implementation of a superclass. Such notes can be implemented with a help of
javadoc.



PLEASE NOTE: JDK6 is formerly known as Project Mustang