6312706: Map entrySet iterators should return different entries on each call to next()
Reviewed-by: mduigou, alanb
Contributed-by: Neil Richards <neil.richards@ngmr.net>
--- a/jdk/src/share/classes/java/util/EnumMap.java Mon Apr 04 11:55:05 2011 -0700
+++ b/jdk/src/share/classes/java/util/EnumMap.java Wed Apr 06 09:31:13 2011 -0700
@@ -106,7 +106,7 @@
/**
* Distinguished non-null value for representing null values.
*/
- private static final Object NULL = new Object();
+ private static final Object NULL = new Integer(0);
private Object maskNull(Object value) {
return (value == null ? NULL : value);
@@ -116,7 +116,7 @@
return (V) (value == NULL ? null : value);
}
- private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
+ private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
/**
* Creates an empty enum map with the specified key type.
@@ -464,6 +464,7 @@
public Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
+
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
@@ -552,70 +553,82 @@
}
}
- /**
- * Since we don't use Entry objects, we use the Iterator itself as entry.
- */
- private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>>
- implements Map.Entry<K,V>
- {
+ private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
+ private Entry lastReturnedEntry = null;
+
public Map.Entry<K,V> next() {
if (!hasNext())
throw new NoSuchElementException();
- lastReturnedIndex = index++;
- return this;
- }
-
- public K getKey() {
- checkLastReturnedIndexForEntryUse();
- return keyUniverse[lastReturnedIndex];
+ lastReturnedEntry = new Entry(index++);
+ return lastReturnedEntry;
}
- public V getValue() {
- checkLastReturnedIndexForEntryUse();
- return unmaskNull(vals[lastReturnedIndex]);
- }
-
- public V setValue(V value) {
- checkLastReturnedIndexForEntryUse();
- V oldValue = unmaskNull(vals[lastReturnedIndex]);
- vals[lastReturnedIndex] = maskNull(value);
- return oldValue;
+ public void remove() {
+ lastReturnedIndex =
+ ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+ super.remove();
+ lastReturnedEntry.index = lastReturnedIndex;
+ lastReturnedEntry = null;
}
- public boolean equals(Object o) {
- if (lastReturnedIndex < 0)
- return o == this;
+ private class Entry implements Map.Entry<K,V> {
+ private int index;
+
+ private Entry(int index) {
+ this.index = index;
+ }
+
+ public K getKey() {
+ checkIndexForEntryUse();
+ return keyUniverse[index];
+ }
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry e = (Map.Entry)o;
- V ourValue = unmaskNull(vals[lastReturnedIndex]);
- Object hisValue = e.getValue();
- return e.getKey() == keyUniverse[lastReturnedIndex] &&
- (ourValue == hisValue ||
- (ourValue != null && ourValue.equals(hisValue)));
- }
+ public V getValue() {
+ checkIndexForEntryUse();
+ return unmaskNull(vals[index]);
+ }
+
+ public V setValue(V value) {
+ checkIndexForEntryUse();
+ V oldValue = unmaskNull(vals[index]);
+ vals[index] = maskNull(value);
+ return oldValue;
+ }
+
+ public boolean equals(Object o) {
+ if (index < 0)
+ return o == this;
- public int hashCode() {
- if (lastReturnedIndex < 0)
- return super.hashCode();
+ if (!(o instanceof Map.Entry))
+ return false;
- Object value = vals[lastReturnedIndex];
- return keyUniverse[lastReturnedIndex].hashCode()
- ^ (value == NULL ? 0 : value.hashCode());
- }
+ Map.Entry e = (Map.Entry)o;
+ V ourValue = unmaskNull(vals[index]);
+ Object hisValue = e.getValue();
+ return (e.getKey() == keyUniverse[index] &&
+ (ourValue == hisValue ||
+ (ourValue != null && ourValue.equals(hisValue))));
+ }
+
+ public int hashCode() {
+ if (index < 0)
+ return super.hashCode();
- public String toString() {
- if (lastReturnedIndex < 0)
- return super.toString();
+ return entryHashCode(index);
+ }
+
+ public String toString() {
+ if (index < 0)
+ return super.toString();
- return keyUniverse[lastReturnedIndex] + "="
- + unmaskNull(vals[lastReturnedIndex]);
- }
+ return keyUniverse[index] + "="
+ + unmaskNull(vals[index]);
+ }
- private void checkLastReturnedIndexForEntryUse() {
- if (lastReturnedIndex < 0)
- throw new IllegalStateException("Entry was removed");
+ private void checkIndexForEntryUse() {
+ if (index < 0)
+ throw new IllegalStateException("Entry was removed");
+ }
}
}
@@ -631,10 +644,35 @@
* @return <tt>true</tt> if the specified object is equal to this map
*/
public boolean equals(Object o) {
- if (!(o instanceof EnumMap))
- return super.equals(o);
+ if (this == o)
+ return true;
+ if (o instanceof EnumMap)
+ return equals((EnumMap)o);
+ if (!(o instanceof Map))
+ return false;
+
+ Map<K,V> m = (Map<K,V>)o;
+ if (size != m.size())
+ return false;
- EnumMap em = (EnumMap)o;
+ for (int i = 0; i < keyUniverse.length; i++) {
+ if (null != vals[i]) {
+ K key = keyUniverse[i];
+ V value = unmaskNull(vals[i]);
+ if (null == value) {
+ if (!((null == m.get(key)) && m.containsKey(key)))
+ return false;
+ } else {
+ if (!value.equals(m.get(key)))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private boolean equals(EnumMap em) {
if (em.keyType != keyType)
return size == 0 && em.size == 0;
@@ -650,6 +688,26 @@
}
/**
+ * Returns the hash code value for this map. The hash code of a map is
+ * defined to be the sum of the hash codes of each entry in the map.
+ */
+ public int hashCode() {
+ int h = 0;
+
+ for (int i = 0; i < keyUniverse.length; i++) {
+ if (null != vals[i]) {
+ h += entryHashCode(i);
+ }
+ }
+
+ return h;
+ }
+
+ private int entryHashCode(int index) {
+ return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
+ }
+
+ /**
* Returns a shallow copy of this enum map. (The values themselves
* are not cloned.
*
@@ -705,9 +763,13 @@
s.writeInt(size);
// Write out keys and values (alternating)
- for (Map.Entry<K,V> e : entrySet()) {
- s.writeObject(e.getKey());
- s.writeObject(e.getValue());
+ int entriesToBeWritten = size;
+ for (int i = 0; entriesToBeWritten > 0; i++) {
+ if (null != vals[i]) {
+ s.writeObject(keyUniverse[i]);
+ s.writeObject(unmaskNull(vals[i]));
+ entriesToBeWritten--;
+ }
}
}
--- a/jdk/src/share/classes/java/util/IdentityHashMap.java Mon Apr 04 11:55:05 2011 -0700
+++ b/jdk/src/share/classes/java/util/IdentityHashMap.java Wed Apr 06 09:31:13 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -829,71 +829,82 @@
}
}
- /**
- * Since we don't use Entry objects, we use the Iterator
- * itself as an entry.
- */
private class EntryIterator
extends IdentityHashMapIterator<Map.Entry<K,V>>
- implements Map.Entry<K,V>
{
+ private Entry lastReturnedEntry = null;
+
public Map.Entry<K,V> next() {
- nextIndex();
- return this;
+ lastReturnedEntry = new Entry(nextIndex());
+ return lastReturnedEntry;
}
- public K getKey() {
- // Provide a better exception than out of bounds index
- if (lastReturnedIndex < 0)
- throw new IllegalStateException("Entry was removed");
-
- return (K) unmaskNull(traversalTable[lastReturnedIndex]);
- }
-
- public V getValue() {
- // Provide a better exception than out of bounds index
- if (lastReturnedIndex < 0)
- throw new IllegalStateException("Entry was removed");
-
- return (V) traversalTable[lastReturnedIndex+1];
+ public void remove() {
+ lastReturnedIndex =
+ ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+ super.remove();
+ lastReturnedEntry.index = lastReturnedIndex;
+ lastReturnedEntry = null;
}
- public V setValue(V value) {
- // It would be mean-spirited to proceed here if remove() called
- if (lastReturnedIndex < 0)
- throw new IllegalStateException("Entry was removed");
- V oldValue = (V) traversalTable[lastReturnedIndex+1];
- traversalTable[lastReturnedIndex+1] = value;
- // if shadowing, force into main table
- if (traversalTable != IdentityHashMap.this.table)
- put((K) traversalTable[lastReturnedIndex], value);
- return oldValue;
- }
+ private class Entry implements Map.Entry<K,V> {
+ private int index;
+
+ private Entry(int index) {
+ this.index = index;
+ }
+
+ public K getKey() {
+ checkIndexForEntryUse();
+ return (K) unmaskNull(traversalTable[index]);
+ }
- public boolean equals(Object o) {
- if (lastReturnedIndex < 0)
- return super.equals(o);
+ public V getValue() {
+ checkIndexForEntryUse();
+ return (V) traversalTable[index+1];
+ }
+
+ public V setValue(V value) {
+ checkIndexForEntryUse();
+ V oldValue = (V) traversalTable[index+1];
+ traversalTable[index+1] = value;
+ // if shadowing, force into main table
+ if (traversalTable != IdentityHashMap.this.table)
+ put((K) traversalTable[index], value);
+ return oldValue;
+ }
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry e = (Map.Entry)o;
- return e.getKey() == getKey() &&
- e.getValue() == getValue();
- }
+ public boolean equals(Object o) {
+ if (index < 0)
+ return super.equals(o);
+
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry e = (Map.Entry)o;
+ return (e.getKey() == unmaskNull(traversalTable[index]) &&
+ e.getValue() == traversalTable[index+1]);
+ }
+
+ public int hashCode() {
+ if (lastReturnedIndex < 0)
+ return super.hashCode();
- public int hashCode() {
- if (lastReturnedIndex < 0)
- return super.hashCode();
+ return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
+ System.identityHashCode(traversalTable[index+1]));
+ }
+
+ public String toString() {
+ if (index < 0)
+ return super.toString();
- return System.identityHashCode(getKey()) ^
- System.identityHashCode(getValue());
- }
+ return (unmaskNull(traversalTable[index]) + "="
+ + traversalTable[index+1]);
+ }
- public String toString() {
- if (lastReturnedIndex < 0)
- return super.toString();
-
- return getKey() + "=" + getValue();
+ private void checkIndexForEntryUse() {
+ if (index < 0)
+ throw new IllegalStateException("Entry was removed");
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/EnumMap/DistinctEntrySetElements.java Wed Apr 06 09:31:13 2011 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 6312706
+ * @summary Sets from Map.entrySet() return distinct objects for each Entry
+ * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
+ */
+
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class DistinctEntrySetElements {
+ static enum TestEnum { e00, e01, e02 }
+
+ public static void main(String[] args) throws Exception {
+ final EnumMap<TestEnum, String> enumMap = new EnumMap<>(TestEnum.class);
+
+ for (TestEnum e : TestEnum.values()) {
+ enumMap.put(e, e.name());
+ }
+
+ Set<Map.Entry<TestEnum, String>> entrySet = enumMap.entrySet();
+ HashSet<Map.Entry<TestEnum, String>> hashSet = new HashSet<>(entrySet);
+
+ if (false == hashSet.equals(entrySet)) {
+ throw new RuntimeException("Test FAILED: Sets are not equal.");
+ }
+ if (hashSet.hashCode() != entrySet.hashCode()) {
+ throw new RuntimeException("Test FAILED: Set's hashcodes are not equal.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/EnumMap/EntrySetIteratorRemoveInvalidatesEntry.java Wed Apr 06 09:31:13 2011 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 6312706
+ * @summary Iterator.remove() from Map.entrySet().iterator() invalidates returned Entry.
+ * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
+ */
+
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class EntrySetIteratorRemoveInvalidatesEntry {
+ static enum TestEnum { e00, e01, e02 }
+
+ public static void main(String[] args) throws Exception {
+ final EnumMap<TestEnum, String> enumMap = new EnumMap<>(TestEnum.class);
+
+ for (TestEnum e : TestEnum.values()) {
+ enumMap.put(e, e.name());
+ }
+
+ Iterator<Map.Entry<TestEnum, String>> entrySetIterator =
+ enumMap.entrySet().iterator();
+ Map.Entry<TestEnum, String> entry = entrySetIterator.next();
+
+ entrySetIterator.remove();
+
+ try {
+ entry.getKey();
+ throw new RuntimeException("Test FAILED: Entry not invalidated by removal.");
+ } catch (Exception e) { }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/EnumMap/SimpleSerialization.java Wed Apr 06 09:31:13 2011 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 6312706
+ * @summary A serialized EnumMap can be successfully de-serialized.
+ * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.EnumMap;
+
+public class SimpleSerialization {
+ private enum TestEnum { e00, e01, e02, e03, e04, e05, e06, e07 }
+ public static void main(final String[] args) throws Exception {
+ final EnumMap<TestEnum, String> enumMap = new EnumMap<>(TestEnum.class);
+
+ enumMap.put(TestEnum.e01, TestEnum.e01.name());
+ enumMap.put(TestEnum.e04, TestEnum.e04.name());
+ enumMap.put(TestEnum.e05, TestEnum.e05.name());
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final ObjectOutputStream oos = new ObjectOutputStream(baos);
+
+ oos.writeObject(enumMap);
+ oos.close();
+
+ final byte[] data = baos.toByteArray();
+ final ByteArrayInputStream bais = new ByteArrayInputStream(data);
+ final ObjectInputStream ois = new ObjectInputStream(bais);
+
+ final Object deserializedObject = ois.readObject();
+ ois.close();
+
+ if (false == enumMap.equals(deserializedObject)) {
+ throw new RuntimeException(getFailureText(enumMap, deserializedObject));
+ }
+ }
+
+ private static String getFailureText(final Object orig, final Object copy) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw);
+
+ pw.println("Test FAILED: Deserialized object is not equal to the original object");
+ pw.print("\tOriginal: ");
+ printObject(pw, orig).println();
+ pw.print("\tCopy: ");
+ printObject(pw, copy).println();
+
+ pw.close();
+ return sw.toString();
+ }
+
+ private static PrintWriter printObject(final PrintWriter pw, final Object o) {
+ pw.printf("%s@%08x", o.getClass().getName(), System.identityHashCode(o));
+ return pw;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/IdentityHashMap/DistinctEntrySetElements.java Wed Apr 06 09:31:13 2011 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 6312706
+ * @summary Sets from Map.entrySet() return distinct objects for each Entry
+ * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
+ */
+
+import java.util.IdentityHashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class DistinctEntrySetElements {
+ public static void main(String[] args) throws Exception {
+ final IdentityHashMap<String, String> identityHashMap =
+ new IdentityHashMap<>();
+
+ identityHashMap.put("One", "Un");
+ identityHashMap.put("Two", "Deux");
+ identityHashMap.put("Three", "Trois");
+
+ Set<Map.Entry<String, String>> entrySet = identityHashMap.entrySet();
+ HashSet<Map.Entry<String, String>> hashSet = new HashSet<>(entrySet);
+
+ // NB: These comparisons are valid in this case because none of the
+ // keys put into 'identityHashMap' above are equal to any other.
+ if (false == hashSet.equals(entrySet)) {
+ throw new RuntimeException("Test FAILED: Sets are not equal.");
+ }
+ if (hashSet.hashCode() != entrySet.hashCode()) {
+ throw new RuntimeException("Test FAILED: Set's hashcodes are not equal.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/IdentityHashMap/EntrySetIteratorRemoveInvalidatesEntry.java Wed Apr 06 09:31:13 2011 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 6312706
+ * @summary Iterator.remove() from Map.entrySet().iterator() invalidates returned Entry.
+ * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
+ */
+
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class EntrySetIteratorRemoveInvalidatesEntry {
+ public static void main(String[] args) throws Exception {
+ final IdentityHashMap<String, String> identityHashMap =
+ new IdentityHashMap<>();
+
+ identityHashMap.put("One", "Un");
+ identityHashMap.put("Two", "Deux");
+ identityHashMap.put("Three", "Trois");
+
+ Iterator<Map.Entry<String, String>> entrySetIterator =
+ identityHashMap.entrySet().iterator();
+ Map.Entry<String, String> entry = entrySetIterator.next();
+
+ entrySetIterator.remove();
+
+ try {
+ entry.getKey();
+ throw new RuntimeException("Test FAILED: Entry not invalidated by removal.");
+ } catch (Exception e) { }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/DistinctEntrySetElements.java Wed Apr 06 09:31:13 2011 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 6312706
+ * @summary Sets from Map.entrySet() return distinct objects for each Entry
+ * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
+ */
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class DistinctEntrySetElements {
+ public static void main(String[] args) throws Exception {
+ final ConcurrentHashMap<String, String> concurrentHashMap =
+ new ConcurrentHashMap<>();
+
+ concurrentHashMap.put("One", "Un");
+ concurrentHashMap.put("Two", "Deux");
+ concurrentHashMap.put("Three", "Trois");
+
+ Set<Map.Entry<String, String>> entrySet = concurrentHashMap.entrySet();
+ HashSet<Map.Entry<String, String>> hashSet = new HashSet<>(entrySet);
+
+ if (false == hashSet.equals(entrySet)) {
+ throw new RuntimeException("Test FAILED: Sets are not equal.");
+ }
+ if (hashSet.hashCode() != entrySet.hashCode()) {
+ throw new RuntimeException("Test FAILED: Set's hashcodes are not equal.");
+ }
+ }
+}