Apply patch and test case for HARMONY-6419 ([classlib][luni] Changes to IdentityHashMap entrySet doesn't reflect underlying map)


git-svn-id: https://svn.apache.org/repos/asf/harmony/enhanced/java/trunk@1043880 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java b/classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java
index 053de1d..8627d03 100644
--- a/classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java
+++ b/classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java
@@ -83,8 +83,16 @@
     private static final Object NULL_OBJECT = new Object();  //$NON-LOCK-1$
 
     static class IdentityHashMapEntry<K, V> extends MapEntry<K, V> {
-        IdentityHashMapEntry(K theKey, V theValue) {
-            super(theKey, theValue);
+
+        final Object iKey;
+
+        final Object[] elementData;
+
+        IdentityHashMapEntry(K theKey, V theValue, Object[] elementData) {
+            super((K) theKey == NULL_OBJECT ? null : theKey,
+                    (V) theValue == NULL_OBJECT ? null : theValue);
+            iKey = theKey;
+            this.elementData = elementData;
         }
 
         @Override
@@ -98,7 +106,7 @@
                 return true;
             }
             if (object instanceof Map.Entry) {
-                Map.Entry<?, ?> entry = (Map.Entry) object;
+                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
                 return (key == entry.getKey()) && (value == entry.getValue());
             }
             return false;
@@ -114,6 +122,14 @@
         public String toString() {
             return key + "=" + value; //$NON-NLS-1$
         }
+
+        public V setValue(V object) {
+            int index = findIndex(iKey, elementData);
+            if (elementData[index] == key) {
+                elementData[index + 1] = object;
+            }
+            return super.setValue(object);
+        }
     }
 
     static class IdentityHashMapIterator<E, KT, VT> implements Iterator<E> {
@@ -208,7 +224,7 @@
         @Override
         public boolean remove(Object object) {
             if (contains(object)) {
-                associatedMap.remove(((Map.Entry) object).getKey());
+                associatedMap.remove(((Map.Entry<?, ?>) object).getKey());
                 return true;
             }
             return false;
@@ -218,7 +234,7 @@
         public boolean contains(Object object) {
             if (object instanceof Map.Entry) {
                 IdentityHashMapEntry<?, ?> entry = associatedMap
-                        .getEntry(((Map.Entry) object).getKey());
+                        .getEntry(((Map.Entry<?, ?>) object).getKey());
                 // we must call equals on the entry obtained from "this"
                 return entry != null && entry.equals(object);
             }
@@ -397,24 +413,15 @@
      */
     @SuppressWarnings("unchecked")
     private IdentityHashMapEntry<K, V> getEntry(int index) {
-        Object key = elementData[index];
-        Object value = elementData[index + 1];
-
-        if (key == NULL_OBJECT) {
-            key = null;
-        }
-        if (value == NULL_OBJECT) {
-            value = null;
-        }
-
-        return new IdentityHashMapEntry<K, V>((K) key, (V) value);
+        return new IdentityHashMapEntry<K, V>((K) elementData[index],
+                (V) elementData[index + 1], elementData);
     }
 
     /**
      * Returns the index where the key is found at, or the index of the next
      * empty spot if the key is not found in this table.
      */
-    private int findIndex(Object key, Object[] array) {
+    private static int findIndex(Object key, Object[] array) {
         int length = array.length;
         int index = getModuloHash(key, length);
         int last = (index + length - 2) % length;
@@ -431,7 +438,7 @@
         return index;
     }
 
-    private int getModuloHash(Object key, int length) {
+    private static int getModuloHash(Object key, int length) {
         return ((System.identityHashCode(key) & 0x7FFFFFFF) % (length / 2)) * 2;
     }
 
@@ -729,7 +736,7 @@
             return true;
         }
         if (object instanceof Map) {
-            Map<?, ?> map = (Map) object;
+            Map<?, ?> map = (Map<?, ?>) object;
             if (size() != map.size()) {
                 return false;
             }
@@ -789,7 +796,7 @@
         stream.writeInt(size);
         Iterator<?> iterator = entrySet().iterator();
         while (iterator.hasNext()) {
-            MapEntry<?, ?> entry = (MapEntry) iterator.next();
+            MapEntry<?, ?> entry = (MapEntry<?, ?>) iterator.next();
             stream.writeObject(entry.key);
             stream.writeObject(entry.value);
         }
diff --git a/classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java b/classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java
index 83ef5e0..4363fe0 100644
--- a/classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java
+++ b/classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java
@@ -25,6 +25,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.Map.Entry;
 
 import org.apache.harmony.testframework.serialization.SerializationTest;
 import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert;
@@ -409,6 +410,25 @@
         assertEquals(cloneHashMap, ((IdentityHashMap) cloneHashMap)
                 .get((Object) null));
     }
+    
+    /*
+     * Regression test for HARMONY-6419
+     */
+    public void test_underlyingMap() {
+        IdentityHashMap<String, String> ihm = new IdentityHashMap<String, String>();
+        String key = "key";
+        String value = "value";
+        ihm.put(key, value);
+
+        Set<Entry<String, String>> set = ihm.entrySet();
+        assertEquals(1, set.size());
+
+        Entry<String, String> entry = set.iterator().next();
+
+        String newValue = "newvalue";
+        entry.setValue(newValue);
+        assertSame(newValue, ihm.get(key)); 
+    }
 
     // comparator for IdentityHashMap objects
     private static final SerializableAssert COMPARATOR = new SerializableAssert() {