Saving and Reloading Data with File Serialization in Java

Serialization from GeeksForGeeks (First Source)

Recently I was working on a project for my IB Computer Science class and was presented with the task of saving and reloading multiple objects to a text file before reloading them back into the same program. For background on my project, I created multiple classes which could inherit from one another to make a very basic character customizer for the game Kirby (only the best video game). In this article I will be explaining how I saved and reloaded any data I had created. You can find the GitHub repository of the full program here: https://github.com/yumibyte/CSMidterm

Project Run Through
In my project I had the Foods and Skills classes which could create different Foods objects and Skills objects for my main Kirby class, which would ultimately effect the defensive/offensive levels of my character. When I was attempting to save the multiple Foods objects, Skills objects, and the single Kirby object, I ran into this error:

NotSerializableException on both my Scanner and on any subclasses I had (in fact, when I attempted to serialize any subclasses, let’s just say my screen was very, very red).

Below is how I solved this issue…

Setting up Your Project to be Serializable
Serialization is necessary because any variables changed in your project are volatile. Thus, serialization helps to transform these objects into arbitrary IDs which can be deserialized and used in the future through reading and writing these IDs from a file.

First begin by implementing serializable so the Java compiler knows what to encode.

public static class Foods implements Serializable {
// variable declarations will go here...

If you have multiple classes inheriting from each other (like I do), implement Serializable at the lowest level. The ability to serialize the objects will be inherited.

Dealing with Non-Serializable Objects

Objects like Scanner are not serializable (I believe this is something to do with it being a separate class of its own which does not have serialization capabilities implemented). Thus, you have to make it transient which means Java will not try to serialize it. Any other variables can be left alone. In my case I also had multiple Foods objects that were created (kirbyFoods ArrayList) and Java will deal with all of these individual objects effectively as long as the main class is serializable. Remember to make any other Scanner instances transient if they are located in your other subclasses.

public static class Foods implements Serializable {
transient Scanner sc = new Scanner(System.in);
private ArrayList<Foods> kirbyFoods = new ArrayList<Foods>();
private String foodName;
private double healAmount;
// do some more functionality with class...
}

Write Objects to a File

We’re now going to create a method for writing to a file. This can be done on the highest level class. ObjectOutputStream will allow for you to write objects to the stream (essentially use I/O’s for any instances you’ve created). I wrote this in my top level class for all of my subclasses, placing it in the Kirby class.

private void writeToFile (ObjectOutputStream out) throws IOException {
out.writeObject(this);
out.close();

In your main class (with public static void…), you can now add some functionality to call writeToFile from the Kirby class.

// leave within try/catch so any errors return to this level from  // the writeToFile func
try (FileOutputStream f = new FileOutputStream("kirbyInfo.txt");

A try/catch is necessary in case writing to the file fails. You also need to specify the file you will be reading from, which is defined as f. Next, s will use the file it has located from f to create a way for you to write your main object to the file. In this case I wrote mainKirby (instance of top level Kirby class) to the ObjectOutputStream s because mainKirby contains all of my other subclasses (it will have all attributes related to Foods objects and Skills objects). I performed this code in my main class with the user menu under a switch/case structure where the user could input if they’d like to “save the game”.

This method should successfully write your data to your desired file.

Reading Class Data

To read the data from the file you need to perform deserialization. Below I created a readFile function to do so. This can be performed in the top level class also which contains all of the other subclasses, as I deserialized the data in the Kirby class.

protected Kirby readFile() throws IOException {

Above we have done the same as writing to the file, rather using the FileInputStream. I had this function return the Kirby character so the main class could redefine all of its attributes related to mainKirby loaded in in from the file.

I similarly called it in a case/switch structure in the main class (public static…) and set it equal to the current instance of my Kirby object which contains all of the character’s stats.

mainKirby = mainKirby.readFile();

And that should be it! You should know be able to save and load classes and its related subclasses in Java. Any constructive criticism is welcome :)

Happy coding ❤

Here are my references:

https://www.geeksforgeeks.org/serialization-in-java/

Here are my references: https://stackoverflow.com/questions/5367916/cant-serialize-an-arraylist

I am a student interested in AI and promoting diversity in tech :)