JDK-7164256 : EnumMap clone doesn't clear the entrySet keeping a reference to the original Map
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,windows_7
  • CPU: x86
  • Submitted: 2012-04-25
  • Updated: 2019-07-10
  • Resolved: 2012-06-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u40Fixed 8 b43Fixed
Description
FULL PRODUCT VERSION :
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) 64-Bit Server VM (build 22.1-b02, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux medea 2.6.35-32-generic #67-Ubuntu SMP Mon Mar 5 19:39:49 UTC 2012 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
The EnumMap clone implementation does not clear the field entrySet. Therefore, any call to the method entrySet in a cloned map (with its entrySet initialized) ) will return a reference to the original entrySet instead of returning a new entrySet pointing to the new map instance.

This breaks the Map.entrySet contract which states " Returns a Set view of the mappings contained in this map"

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
This happens every time a EnumMap,  which has its entrySet initialized, is cloned. All changes made to the new instance won't be reflected by the EntrySet returned by the entrySet() method.

Example:

import java.util.EnumMap;
import java.util.Map.Entry;


public class TestEnumMap {
    public enum Test {
        ONE, TWO
    }

    public static void main(String[] args) {
        EnumMap<Test, String> map1 = new EnumMap<Test, String>(Test.class);
        map1.put(Test.ONE, "1");
        map1.put(Test.TWO, "2");

        for (Entry<Test, String> entry : map1.entrySet()) {
            System.out.println(entry);
        }

        System.out.println("---------------");

        EnumMap<Test, String> map2 = map1.clone();
        map2.remove(Test.ONE);
        for (Entry<Test, String> entry : map2.entrySet()) {
            System.out.println(entry);
        }
    }
}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
ONE=1
TWO=2
---------------
TWO=2

ACTUAL -
ONE=1
TWO=2
---------------
ONE=1
TWO=2


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.EnumMap;
import java.util.Map.Entry;


public class TestEnumMap {
    public enum Test {
        ONE, TWO
    }

    public static void main(String[] args) {
        EnumMap<Test, String> map1 = new EnumMap<Test, String>(Test.class);
        map1.put(Test.ONE, "1");
        map1.put(Test.TWO, "2");

        for (Entry<Test, String> entry : map1.entrySet()) {
            System.out.println(entry);
        }

        System.out.println("---------------");

        EnumMap<Test, String> map2 = map1.clone();
        map2.remove(Test.ONE);
        for (Entry<Test, String> entry : map2.entrySet()) {
            System.out.println(entry);
        }
    }
}
---------- END SOURCE ----------

Comments
EVALUATION http://hg.openjdk.java.net/jdk8/tl/jdk/rev/757a5129fad7
07-06-2012