JDK-4756277 : (coll) HashMap's keySet(), entrySet() and values() are not serializable
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 1.3.1
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-10-01
  • Updated: 2012-10-08
  • Resolved: 2011-04-05
Related Reports
Duplicate :  
Relates :  
Description

Name: gm110360			Date: 10/01/2002


FULL PRODUCT VERSION :
Occurs in both 1.3.0 and 1.3.1:

java version "1.3.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0_02)
Java HotSpot(TM) Client VM (build 1.3.0_02, mixed mode)

java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]
(Service Pack 2)

A DESCRIPTION OF THE PROBLEM :
The collections returned by calls to
java.util.HashMap#entrySet, #keySet and #values are not
Serializable which, although consistent with the
documentation, is confusing and counter-intuitive because
HashMap itself is Serializable.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a HashMap.
2. Attempt to serialize the result of calling keySet(),
entrySet() or values() on that HashMap.


EXPECTED VERSUS ACTUAL BEHAVIOR :
I would (naively, optimistically :-) assume these
collections to be Serializable, since the object from which
they come is itself Serializable.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
keySet():
Trying to serialize [two, one, three]...failed:
java.io.NotSerializableException: java.util.HashMap$1
        at java.io.ObjectOutputStream.outputObject(ObjectOutputStream.java:1148)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:366)
        at
test.MapCollectionsSerializeMain.trySerialize(MapCollectionsSerializeMain.java:15)
        at
test.MapCollectionsSerializeMain.main(MapCollectionsSerializeMain.java:36)
entrySet():
Trying to serialize [two=two, one=one, three=three]...failed:
java.io.NotSerializableException: java.util.HashMap$3
        at java.io.ObjectOutputStream.outputObject(ObjectOutputStream.java:1148)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:366)
        at
test.MapCollectionsSerializeMain.trySerialize(MapCollectionsSerializeMain.java:15)
        at
test.MapCollectionsSerializeMain.main(MapCollectionsSerializeMain.java:38)
values():
Trying to serialize [two, one, three]...failed:
java.io.NotSerializableException: java.util.HashMap$2
        at java.io.ObjectOutputStream.outputObject(ObjectOutputStream.java:1148)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:366)
        at
test.MapCollectionsSerializeMain.trySerialize(MapCollectionsSerializeMain.java:15)
        at
test.MapCollectionsSerializeMain.main(MapCollectionsSerializeMain.java:40)

REPRODUCIBILITY :
This bug can be reproduced rarely.

---------- BEGIN SOURCE ----------
package test;

import java.io.*;
import java.util.*;

public class MapCollectionsSerializeMain
{

    private static void trySerialize (Object o) {
        try {
            ObjectOutputStream stream
                = new ObjectOutputStream(new ByteArrayOutputStream());
            System.out.print("Trying to serialize " + o + "...");
            stream.writeObject(o);
            stream.flush();
            System.out.println("done");
        }
        catch (Exception e) {
            System.out.print("failed: ");
            e.printStackTrace();
        }
    }

    // ----------------------------------------------------------------------
    // Entry point

    public static void main (String[] args) {

        Map map = new HashMap();
        map.put("one", "one");
        map.put("two", "two");
        map.put("three", "three");

        System.out.println("keySet():");
        trySerialize(map.keySet());
        System.out.println("entrySet():");
        trySerialize(map.entrySet());
        System.out.println("values():");
        trySerialize(map.values());

    }
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
For the keySet() and valueSet() cases, one could create a
new HashSet from those sets, but that's inefficient and it
doesn't cover the values() case.

The right answer in the first place is presumably that any
Serializable object which contains a Set (or other abstract
type not documented as Serializable) must implement its own
readObject and writeObject methods which (de-)serialize the
set manually.  Either that, or define the object to contain
a HashSet (or other type documented as Serializable).
(Review ID: 165184) 
======================================================================

Comments
EVALUATION The results of keySet(), entrySet() and values() are only views onto the collection and are not serializable independently. The view collections are intentionally not serializable. Serializing collection views has very strange semantics. The underlying collection would likely have to be serialized as well, but would then be inaccessible when de-serialized? This is an odd and probably bad situation.
05-04-2011