HashMap not Serializable
Asked Answered
E

2

7

HashMap with Serializable key/value is supposed to be Serializable.

But it's not working for me. Tried some other IO streams. None works.

Any suggestion?

Test code

public class SimpleSerializationTest {
    @Test
    public void testHashMap() throws Exception {
        HashMap<String, String> hmap = new HashMap<String, String>() {{
            put(new String("key"), new String("value"));
        }};

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutput out = null;
        out = new ObjectOutputStream(bos);
        out.writeObject(hmap);
        byte[] yourBytes = bos.toByteArray();
        if (out != null) {
            out.close();
        }
        bos.close();

        ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
        ObjectInput in = null;
        in = new ObjectInputStream(bis);
        Object o = in.readObject();
        bis.close();
        if (in != null) {
            in.close();
        }

        assertEquals(hmap, o);
    }
}

Stack trace

java.io.NotSerializableException: SimpleSerializationTest
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at SimpleSerializationTest.testHashMap(SimpleSerializationTest.java:18)

Process finished with exit code 0
Erastes answered 25/9, 2015 at 20:18 Comment(2)
Tried it on my local.it runs without any exception.It seems you are not importing proper class files?Can you share that?Rest looks fine to me.Atmolysis
Don't write new String("key"), just write "key". A literal such as "key" is already a String object. You do not need to explicitly create a copy of that String object.Upward
H
19

The exception message tells you exactly what the problem is: you are trying to serialize an instance of class SimpleSerializationTest, and that class is not serializable.

Why? Well, you have created an anonymous inner class of SimpleSerializationTest, one that extends HashMap, and you are trying to serialize an instance of that class. Inner classes always have references to the relevant instance of their outer class, and by default, serialization will try to traverse those.

I observe that you use a double-brace {{ ... }} syntax as if you think it has some sort of special significance. It is important to understand that it is actually two separate constructs. The outer pair of braces appearing immediately after a constructor invocation mark the boundaries of the inner class definition. The inner pair bound an instance initializer block, such as you can use in any class body (though they are unusual in contexts other than anonymous inner classes). Ordinarily, you would also include one or more method implementations / overrides inside the outer pair, either before or after the initializer block.

Try this instead:

    public void testHashMap() throws Exception {
        Map<String, String> hmap = new HashMap<String, String>();

        hmap.put(new String("key"), "value");

        // ...
    }
Humperdinck answered 25/9, 2015 at 20:27 Comment(8)
Makes sense, but when I run OP's code exactly, it serializes alright. Why is that?Philipps
@Philipps Perhaps you are doing it from static context?Happily
@sstan, Using the OP's code verbatim, I can exactly reproduce the exception the he reported.Humperdinck
Use diamond operator.Airborne
Cool. Did't realize it created an anonymous inner class. Then how do I use Lambda to simplify the object initialization in such situations?Erastes
@Puce, that's sound advice. For this answer, however, I retained those from the OP's code to avoid any impression that they make a difference with respect to serialization.Humperdinck
@datree, if you could use a lambda here, you would do so by passing it as a constructor argument. HashMap has no constructor that accepts a functional interface type as an argument, however, so there is no opportunity to use a lambda. The only other alternative would be to use some sort of factory class that accepts a lambda and uses it to construct a Map for you, and at that point I think we've lost sight of "simplify[ing]".Humperdinck
As StackOverflow answers are potentially used by many visitors I recommend to clean up code when writing answers, so visitors really learn best practices.Airborne
C
0

A working version of your code :

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;

import org.junit.Test;

import junit.framework.Assert;

public class SimpleSerializationTest implements Serializable{
    @Test
public void testHashMap() throws Exception {
    HashMap<String, String> hmap = new HashMap<String, String>() {{
        put(new String("key"), new String("value"));
    }};

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutput out = null;
    out = new ObjectOutputStream(bos);
    out.writeObject(hmap);
    byte[] yourBytes = bos.toByteArray();
    if (out != null) {
        out.close();
    }
    bos.close();

    ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
    ObjectInput in = null;
        in = new ObjectInputStream(bis);
        HashMap<String, String> o = (HashMap<String, String>) in.readObject();
        bis.close();
        if (in != null) {
            in.close();
        }

        Assert.assertEquals(hmap, o);
    }
}
Chamonix answered 25/9, 2015 at 20:57 Comment(1)
Well, ok, as long as the test class doesn't have a non-serializable instance member. It would be better under most circumstances to just avoid the inner class and any associated reliance on the host class being serializable.Humperdinck

© 2022 - 2024 — McMap. All rights reserved.