javaserializationioobjectoutputstreamnotserializableexception

Why I receive NotSerializableException while attempting to Serialize an Object


I have the following class:

public class GameWorld implements Serializable {
    int sumu_dist = 30;
    public List<Tiles> tileGroup = new ArrayList<>();
    public List<Tiles> loadingTiles = new ArrayList<>();

    // constructor etc.
}

in another class, I tried to save GameWorld, but received not serializable exception:

public class game {

    static GameWorld GameWorldObj = new GameWorld();

    String FileName = "WorldData.bin";

void Save(){
    try {
        FileOutputStream FOS = new FileOutputStream(FileName);
        ObjectOutputStream OOS = new ObjectOutputStream(FOS);
        if (gameworld_obj instanceof Serializable){
            OOS.writeObject(GameWorldObj); // java.io.NotSerializableException
        }
        System.out.printf("SAVED: %s \n", OOS);
        OOS.close();
    } catch (IOException exception){
        System.err.println(String.valueOf(exception));
    } 
    
}   

public static void main(String[] args) {
    new game().Save();
}

I don't know why it's happen, I search on SO and find some answers told you to implement Serializable. I did it, and I'm still receiving NotSerializableException.

Why is that to happen? What can I do to fix it?

Error-message:

java.io.NotSerializableException: source.library.level.Tiles
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1197)
    at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1582)
    at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1539)
    at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1448)
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1191)
    at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
    at source.library.level.game.Save(game.java:33)
    at source.library.level.game.main(game.java:47)

Solution

  • The whole object graph needs to be serializable, if at least one of the fields doesn't implement Serializable interface you'll get an exception while attempting to serialize the instance of this class.

    Quote from the documentation:

    When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object.

    Primitive types and most of the data-types built-in in the JDK are serializable.

    You can run into troubles only with these types:

    If you don't want a particular field to be serialized, you can mark it as transient. Transient fields as well as static fields are ignored during the serialization process.

    So if you would make the fields tileGroup and loadingTiles to be transient, then Tiles class will not be required to implement Serializable because these attributes will be excluded from the serialized version. And as a consiquence after deserialization they will be initialized to null.

    In general, serialization is meant to be used for temporary data-storage or transferring the data. To ensure that an object retrieved from memory is compatible with the .class file that you have it a good practice to define static final long serialVersionUID field, which denotes the current version of the class.

    The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:

    ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

    Also, you should be aware that serialization has some serious draw-backs (take a look at the link provided above).

    Sidenote: class-names are usually singular nouns like Student, Employee, Tile because their instances are meant to represent a single object.