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
RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
datree
  • 483
  • 3
  • 7
  • 14
  • 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. – RockAndRoll Sep 25 '15 at 20:30
  • 1
    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. – Jesper Sep 25 '15 at 21:17

2 Answers2

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");

        // ...
    }
ymajoros
  • 2,454
  • 3
  • 34
  • 60
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Makes sense, but when I run OP's code exactly, it serializes alright. Why is that? – sstan Sep 25 '15 at 20:34
  • 1
    @sstan Perhaps you are doing it from static context? – RealSkeptic Sep 25 '15 at 20:35
  • @sstan, Using the OP's code verbatim, I can exactly reproduce the exception the he reported. – John Bollinger Sep 25 '15 at 20:39
  • Use diamond operator. – Puce Sep 25 '15 at 20:42
  • Cool. Did't realize it created an anonymous inner class. Then how do I use Lambda to simplify the object initialization in such situations? – datree Sep 25 '15 at 20:43
  • 2
    @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. – John Bollinger Sep 25 '15 at 20:43
  • @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]". – John Bollinger Sep 25 '15 at 20:47
  • As StackOverflow answers are potentially used by many visitors I recommend to clean up code when writing answers, so visitors really learn best practices. – Puce Sep 25 '15 at 21:29
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);
    }
}
fabien t
  • 358
  • 1
  • 9
  • 2
    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. – John Bollinger Sep 25 '15 at 21:20