>From my earlier posts:

1. >> Although one (including my good self!) might initially think that
a key-value class and a Map.Entry class are interchangeable, this is
not
in fact the case. DefaultMapEntry is not suitable for use as a general
purpose KeyValue class, as it is effectively non-extendable... [due to
#equals and #hashCode being defined by Map.Entry API doc]

2. >> My suggested solution is to add a class [KeyValuePair.java]
containing the code from DefaultMapEntry, but not implementing
Map.Entry. DefaultMapEntry can then subclass [KeyValuePair] and
implement Map.Entry 


I actually missed the big reason why KeyValuePair and Map.Entry are not
interchangeable. A Map.Entry's key is an invariant, while a
KeyValuePair's key is mutable. The key-invariant property means that
the existing DefaultMapEntry implementation is in fact broken - the
#setKey method should not be present. Note that the Map.Entry impls in
java.util do not feature a key mutator (and of course - far more
importantly - the Map.Entry interface itself does not).

It follows that my suggested solution from (1) above is bogus, as
KeyValuePair has a #setKey method which DefaultMapEntry would inherit.
To retain the key-invariant property, DefaultMapEntry would have to
override #setKey to either (a) silently do nothing, or (b) throw an
UnsupportedOperationException or such; - both horrible options.
Moreover, since the suggested hierarchial relationship between the two
classes was based on a faulty understanding of their similarity, it's
best to ditch that relationship and have the two classes stand alone. 

I've attached implementations/patches to that effect. However, all is
not entirely lost ;) as KeyValuePair has a constructor that takes a
Map.Entry and also has a #toMapEntry method, thus retaining a bridge
between the two classes.

> I'm happy to add it....with a test case :-)
> Stephen

Test class for KeyValuePair attached. Also included is a test class for
DefaultMapEntry (TestMapEntry.java) as it does not appear to have one
(or am I somehow missing it?); also a patch for TestAll to include the
new test classes.

- Neil



/*
 * $Header: 
/home/cvspublic/jakarta-commons/collections/src/java/org/apache/commons/collections/DefaultMapEntry.java,v
 1.11 2003/08/31 17:26:43 scolebourne Exp $
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.apache.commons.collections;

import java.util.Map;

/**
 * A mutable key-value pair. Note that a <code>KeyValuePair</code> instance
 * may not contain itself as a key or value.
 *
 * @since Commons Collections 3.0
 * @version $Revision: $
 * 
 * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a>
 * @author <a href="mailto:[EMAIL PROTECTED]">Michael A. Smith</a>
 * @author Neil O'Toole
 */
public class KeyValuePair
{

        /** The key */
        private Object key;
        /** The value */
        private Object value;

        /**
         * Constructs a new <Code>KeyValuePair</Code> with a null key
         * and null value.
         */
        public KeyValuePair()
        {
        }

        /**
         * Constructs a new <Code>KeyValuePair</Code> with the given
         * key and given value.
         *
         * @param key  the key for the entry, may be null
         * @param value  the value for the entry, may be null
         */
        public KeyValuePair(Object key, Object value)
        {
                this.key = key;
                this.value = value;
        }

        /**
         * Copy constructor.
         */
        public KeyValuePair(KeyValuePair copy)
        {
                this.key = copy.getKey();
                this.value = copy.getValue();
        }

        /**
         * Constructs a new <Code>KeyValuePair</Code> with key
         * and value from the supplied <code>Map.Entry</code>. 
         */
        public KeyValuePair(Map.Entry entry)
        {
                this.key = entry.getKey();
                this.value = entry.getValue();
        }

        /**
         * Returns true if the compared object is also a <code>KeyValuePair</code>,
         * and its key and value are equal to this object's key and value.
         */
        public boolean equals(Object o)
        {
                if (o == this)
                {
                        return true;
                }

                if (o instanceof KeyValuePair == false)
                {
                        return false;
                }

                KeyValuePair kv2 = (KeyValuePair) o;

                return (
                        (getKey() == null ? kv2.getKey() == null : 
getKey().equals(kv2.getKey()))
                                && (getValue() == null ? kv2.getValue() == null : 
getValue().equals(kv2.getValue())));
        }

        /**
         * Generates hashcode as per [EMAIL PROTECTED] Map.Entry#hashCode}, but note 
that
         * subclasses may override this method to provide a more appropriate hash.
         * 
         * @return a hash generated as per the Map.Entry#hashCode javadoc.
         */
        public int hashCode()
        {
                return ((getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == 
null ? 0 : getValue().hashCode()));
        }

        /**
         * Returns the key.
         *
         * @return the key 
         */
        public Object getKey()
        {
                return key;
        }

        /**
         * Returns the value.
         *
         * @return the value
         */
        public Object getValue()
        {
                return value;
        }

        /**
         * Sets the key.
         *
         * @param key  the new key
         * @return the old key
         * @throws IllegalArgumentException if key is this object
         */
        public Object setKey(Object key)
        {
                if (key == this)
                {
                        throw new IllegalArgumentException("A KeyValuePair may not 
contain itself as a key.");
                }
                
                final Object old = this.key;
                this.key = key;
                return old;
        }

        /** 
         * Sets the value.
         *
         * @return the old value of the value
         * @param value the new value
         * @throws IllegalArgumentException if value is this object
         */
        public Object setValue(Object value)
        {
                if (value == this)
                {
                        throw new IllegalArgumentException("A KeyValuePair may not 
contain itself as a value.");
                }
                        
                final Object old = this.value;
                this.value = value;
                return old;
        }

        /**
         * Returns a new <code>Map.Entry</code> object with key and value from this 
<code>KeyValuePair</code>.
         */
        public Map.Entry toMapEntry()
        {
                return new DefaultMapEntry(this.getKey(), this.getValue());
        }

        public String toString()
        {
                return new 
StringBuffer().append(getKey()).append('=').append(getValue()).toString();
        }

}
Index: DefaultMapEntry.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons/collections/src/java/org/apache/commons/collections/DefaultMapEntry.java,v
retrieving revision 1.11
diff -u -r1.11 DefaultMapEntry.java
--- DefaultMapEntry.java        31 Aug 2003 17:26:43 -0000      1.11
+++ DefaultMapEntry.java        25 Sep 2003 05:14:06 -0000
@@ -60,18 +60,26 @@
 import java.util.Map;
 
 /**
- * A default implementation of [EMAIL PROTECTED] java.util.Map.Entry}
+ * A default implementation of [EMAIL PROTECTED] java.util.Map.Entry}. A
+ * <code>Map.Entry</code>'s key cannot be changed, and thus
+ * the key-related fields and methods are final.
+ * 
+ * Additionally, note that the  <code>#equals</code>
+ * and <code>#hashCode</code> methods are implemented as specified by
+ * the <code>Map.Entry</code> API doc, and 
+ * thus these methods are also declared final.
  *
  * @since Commons Collections 1.0
  * @version $Revision: 1.11 $ $Date: 2003/08/31 17:26:43 $
  * 
  * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a>
  * @author <a href="mailto:[EMAIL PROTECTED]">Michael A. Smith</a>
+ * @author Neil O'Toole
  */
 public class DefaultMapEntry implements Map.Entry {
     
     /** The key */
-    private Object key;
+    private final Object key;
     /** The value */
     private Object value;
     
@@ -80,6 +88,7 @@
      * and null value.
      */
     public DefaultMapEntry() {
+       this.key = null;
     }
 
     /**
@@ -93,13 +102,23 @@
         this.key = key;
         this.value = value;
     }
+    
+    
+       /**
+        * Copy constructor - creates a new <Code>DefaultMapEntry</Code> with
+        * key and value from the supplied Map.Entry.
+        *
+        */
+       public DefaultMapEntry(Map.Entry copy) {
+               this.key = copy.getKey();
+               this.value = copy.getValue();
+       }
 
     /**
      * Implemented per API documentation of 
      * [EMAIL PROTECTED] java.util.Map.Entry#equals(Object)}
      */
-    public boolean equals(Object o) {
-        if( o == null ) return false;
+    public final boolean equals(Object o) {
         if( o == this ) return true;        
 
         if ( ! (o instanceof Map.Entry ) )
@@ -116,22 +135,18 @@
      * Implemented per API documentation of 
      * [EMAIL PROTECTED] java.util.Map.Entry#hashCode()}
      */
-    public int hashCode() {
+    public final int hashCode() {
         return ( ( getKey() == null ? 0 : getKey().hashCode() ) ^
                  ( getValue() == null ? 0 : getValue().hashCode() ) ); 
     }
     
 
-
-    // Map.Entry interface
-    //-------------------------------------------------------------------------
-
     /**
      * Returns the key.
      *
      * @return the key 
      */
-    public Object getKey() {
+    public final Object getKey() {
         return key;
     }
 
@@ -144,29 +159,29 @@
         return value;
     }
 
-    // Properties
-    //-------------------------------------------------------------------------    
 
-    /**
-     * Sets the key.  This method does not modify any map.
-     *
-     * @param key  the new key
-     */
-    public void setKey(Object key) {
-        this.key = key;
-    }
-    
     /** 
      * Note that this method only sets the local reference inside this object and
-     * does not modify the original Map.
+     * does not modify any Map.
      *
      * @return the old value of the value
      * @param value the new value
+     * @throws IllegalArgumentException if value is this object. A Map.Entry may not 
contain
+     * itself as a value because Map.Entry's required #hashCode implementation will
+     * enter an infinite recursion.
      */
     public Object setValue(Object value) {
+        if (value == this)
+               throw new IllegalArgumentException("A Map.Entry may not contain itself 
as a value.");
+        
         Object answer = this.value;
         this.value = value;
         return answer;
     }
+    
+       public String toString()
+       {
+               return new 
StringBuffer().append(key).append('=').append(value).toString();
+       }
 
 }
Index: TestAll.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-commons/collections/src/test/org/apache/commons/collections/TestAll.java,v
retrieving revision 1.47
diff -u -r1.47 TestAll.java
--- TestAll.java        20 Sep 2003 16:58:19 -0000      1.47
+++ TestAll.java        25 Sep 2003 05:12:58 -0000
@@ -105,7 +105,9 @@
         suite.addTest(TestFastTreeMap1.suite());
         suite.addTest(TestHashBag.suite());
         suite.addTest(TestIteratorUtils.suite());
+        suite.addTest(TestKeyValuePair.suite());
         suite.addTest(TestLRUMap.suite());
+        suite.addTest(TestMapEntry.suite());
         suite.addTest(TestMultiHashMap.suite());
         suite.addTest(TestMultiKey.suite());
         suite.addTest(TestNodeCachingLinkedList.suite());
/*
 * $Header: 
x:/apps/cvsnt/cvs_repository/main/notifyingcollections/src/test/org/apache/commons/collections/TestKeyValueRecord.java,v
 1.1 2003/09/20 22:00:46 otoolen Exp $
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.apache.commons.collections;

import java.util.HashMap;
import java.util.Map;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * 
 * @author Neil O'Toole
 */
public class TestKeyValuePair extends TestCase
{
        private final String key = "name";
        private final String value = "duke";


        public TestKeyValuePair(String testName)
        {
                super(testName);

        }

        public static void main(String[] args)
        {
                junit.textui.TestRunner.run(TestKeyValuePair.class);
        }


        public static Test suite()
        {
                return new TestSuite(TestKeyValuePair.class);
        }


        public void testAccessorsAndMutators()
        {
                KeyValuePair kv = new KeyValuePair();
                
                kv.setKey(key);
                assertTrue(kv.getKey() == key);
                
                kv.setValue(value);
                assertTrue(kv.getValue() == value);

                // check that null doesn't do anything funny
                kv.setKey(null);
                assertTrue(kv.getKey() == null);
                
                kv.setValue(null);
                assertTrue(kv.getValue() == null);
                
        }
        
        public void testSelfReferenceHandling()
        {
                // test that #setKey and #setValue do not permit
                //  the KVP to contain itself (and thus cause infinite recursion
                //  in #hashCode and #toString)
                
                KeyValuePair kv = new KeyValuePair();
                
                try
                {
                        kv.setKey(kv);
                        fail("Should throw an IllegalArgumentException");
                }
                catch(IllegalArgumentException iae)
                {
                        // expected to happen...
                        
                        // check that the KVP's state has not changed
                        assertTrue(kv.getKey() == null && kv.getValue() == null);
                }
                
                try
                {
                        kv.setValue(kv);
                        fail("Should throw an IllegalArgumentException");
                }
                catch(IllegalArgumentException iae)
                {
                        // expected to happen...
                        
                        // check that the KVP's state has not changed
                        assertTrue(kv.getKey() == null && kv.getValue() == null);
                }
        }
        
        
        public void testConstructors()
        {
                // 1. test default constructor
                KeyValuePair kv = new KeyValuePair();
                assertTrue(kv.getKey() == null && kv.getValue() == null);
                
                        
                // 2. test key-value constructor
                kv = new KeyValuePair(key, value);
                assertTrue(kv.getKey() == key && kv.getValue() == value);
                
                
                // 3. test copy constructor
                KeyValuePair kv2 = new KeyValuePair(kv);
                assertTrue(kv2.getKey() == key && kv2.getValue() == value);
                
                // test that the KVPs are independent
                kv.setKey(null);
                kv.setValue(null);
                
                assertTrue(kv2.getKey() == key && kv2.getValue() == value);
                
                
                
                // 4. test Map.Entry constructor
                Map map = new HashMap();
                map.put(key, value);
                Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
                
                kv = new KeyValuePair(entry);
                assertTrue(kv.getKey() == key && kv.getValue() == value);
                
                // test that the KVP is independent of the Map.Entry
                entry.setValue(null);
                assertTrue(kv.getValue() == value);
                        
        }
        
        public void testEqualsAndHashCode()
        {
                // 1. test with object data
                KeyValuePair kv = new KeyValuePair(key, value);
                KeyValuePair kv2 = new KeyValuePair(key, value);
                
                assertTrue(kv.equals(kv));
                assertTrue(kv.equals(kv2));
                assertTrue(kv.hashCode() == kv2.hashCode());
                
                // 2. test with nulls
                kv = new KeyValuePair();
                kv2 = new KeyValuePair();
                
                assertTrue(kv.equals(kv));
                assertTrue(kv.equals(kv2));
                assertTrue(kv.hashCode() == kv2.hashCode());
        }
        
        public void testToString()
        {
                KeyValuePair kv = new KeyValuePair(key, value);
                assertTrue(kv.toString().equals(kv.getKey() + "=" + kv.getValue()));
                
                // test with nulls
                kv = new KeyValuePair();
                assertTrue(kv.toString().equals(kv.getKey() + "=" + kv.getValue()));
        }
        

        public void testToMapEntry()
        {
                KeyValuePair kv = new KeyValuePair(key, value);
                
                Map map = new HashMap();
                map.put(kv.getKey(), kv.getValue());
                Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
                
                assertTrue(entry.equals(kv.toMapEntry()));
                assertTrue(entry.hashCode() == kv.hashCode());
        }

}
/*
 * $Header: 
x:/apps/cvsnt/cvs_repository/main/notifyingcollections/src/test/org/apache/commons/collections/TestKeyValueRecord.java,v
 1.1 2003/09/20 22:00:46 otoolen Exp $
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.apache.commons.collections;

import java.util.HashMap;
import java.util.Map;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * 
 * @author Neil O'Toole
 */
public class TestMapEntry extends TestCase
{
        private final String key = "name";
        private final String value = "duke";


        public TestMapEntry(String testName)
        {
                super(testName);

        }

        public static void main(String[] args)
        {
                junit.textui.TestRunner.run(TestMapEntry.class);
        }

        public static Test suite()
        {
                return new TestSuite(TestMapEntry.class);
        }

        /**
         * Make an instance of Map.Entry with the default (null) key and value.
         * Subclasses should override this method to return a Map.Entry
         * of the type being tested.
         */
        public Map.Entry makeMapEntry()
        {
                return new DefaultMapEntry();
        }

        /**
         * Make an instance of Map.Entry with the specified key and value.
         * Subclasses should override this method to return a Map.Entry
         * of the type being tested.
         */
        public Map.Entry makeMapEntry(Object key, Object value)
        {
                return new DefaultMapEntry(key, value);
        }

        

        public Map.Entry makeKnownMapEntry()
        {
                return makeKnownMapEntry(null, null);
        }


        public Map.Entry makeKnownMapEntry(Object key, Object value)
        {
                Map map = new HashMap(1);
                map.put(key, value);
                Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
                return entry;
        }


        public void testAccessorsAndMutators()
        {
                Map.Entry entry = makeMapEntry(key, value);
                
                
                assertTrue(entry.getKey() == key);
                
                entry.setValue(value);
                assertTrue(entry.getValue() == value);

                // check that null doesn't do anything funny
                entry = makeMapEntry(null, null);
                assertTrue(entry.getKey() == null);
                
                entry.setValue(null);
                assertTrue(entry.getValue() == null);           
        }
        
        
        public void testSelfReferenceHandling()
        {
                // test that #setValue does not permit
                //  the MapEntry to contain itself (and thus cause infinite recursion
                //  in #hashCode and #toString)

                Map.Entry entry = makeMapEntry();
                
                try
                {
                        entry.setValue(entry);
                        fail("Should throw an IllegalArgumentException");
                }
                catch(IllegalArgumentException iae)
                {
                        // expected to happen...
                        
                        // check that the KVP's state has not changed
                        assertTrue(entry.getKey() == null && entry.getValue() == null);
                }
        }
        
        
        /**
         * Subclasses should override this method.
         *
         */
        public void testConstructors()
        {
                // 1. test default constructor
                Map.Entry entry = new DefaultMapEntry();
                assertTrue(entry.getKey() == null && entry.getValue() == null);
                
                        
                // 2. test key-value constructor
                entry = new DefaultMapEntry(key, value);
                assertTrue(entry.getKey() == key && entry.getValue() == value);
                
                
                // 3. test copy constructor
                Map.Entry entry2 = new DefaultMapEntry(entry);
                assertTrue(entry2.getKey() == key && entry2.getValue() == value);
                
                // test that the objects are independent
                entry.setValue(null);
                
                assertTrue(entry2.getValue() == value);         
        }
        
        public void testEqualsAndHashCode()
        {
                // 1. test with object data
                Map.Entry e1 = makeMapEntry(key, value);
                Map.Entry e2 = makeKnownMapEntry(key, value);
                
                assertTrue(e1.equals(e1));
                assertTrue(e2.equals(e1));
                assertTrue(e1.hashCode() == e2.hashCode());
                
                // 2. test with nulls
                e1 = makeMapEntry();
                e2 = makeKnownMapEntry();
                
                assertTrue(e1.equals(e1));
                assertTrue(e2.equals(e1));
                assertTrue(e1.hashCode() == e2.hashCode());
        }
        
        public void testToString()
        {
                Map.Entry entry = makeMapEntry(key, value);
                assertTrue(entry.toString().equals(entry.getKey() + "=" + 
entry.getValue()));
                
                // test with nulls
                entry = makeMapEntry();
                assertTrue(entry.toString().equals(entry.getKey() + "=" + 
entry.getValue()));
        }
        

}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to