Home > Net >  Why I receive NotSerializableException while attempting to Serialize an Object
Why I receive NotSerializableException while attempting to Serialize an Object

Time:04-19

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)

CodePudding user response:

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:

  • Object doesn't implement Serializable, hence Object type fields are not allowed in the class that is meant to be serializable.
  • Optional as well as OptionalInt, OptionalLong and OptianalDouble aren't serializable because optional types were introduced as limited mechanism for return types and not intended to be used as fields.
  • Your custom types used as a field of a serializable class has to be serializable. Tiles class has to implement Serializable and if there are some custom field types inside the Tiles, they must be serializable as well.

If you don't want a particular field to be serialized, you can mark it as transient. Transient fields as well as static field 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.

  • Related