Question

I have as an assignment (for the OOP course from Uni) a pretty large project: a school register, where students can see their grades, teachers can add grades and so on.

The "base" class is a singleton which contains all the classes (Java) used, such as an array of users, classes (as in school classes) and a TreeMap that associates classess and teachers to courses.

I want to serialize this base class (Central), in order to save the modified data. The problem is that I get this exception

java.io.NotSerializableException: liceu.Central$1
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:440)
at java.util.TreeMap.writeObject(TreeMap.java:2265)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1495)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
at liceu.Main.main(Main.java:31)

All of my classes implement Serializable, and they don't have transient or static fields (except for the singleton, which has the instance variable and getInstance method as statics).

Because it would be quite a lot of code to post (and I would risk to nullify my assignment by publishing it before submitting) I have tried to make a proof of concept by trying to isolate the error.

public class Central implements Serializable
{
    private ArrayList <User> users;
    private ArrayList <Class> classess;
    private TreeMap <Course, TreeMap <Class, Professor>> reunite;
    private static Central instance = null;

    private Central()
    {
        users = new ArrayList<>();
        classess = new ArrayList<>();
        reunite = new TreeMap<>(new Comparator<Student>(){
            @Override
            public int compare(Student e1, Student e2)
            {
                return e1.getName().compareTo(e2.getName());
            }
        });
    }
}

If I keep only the first 2 ArrayLists, the serialization process works. The problem is with the TreeMap.

Is the TreeMap class serializable? (In general) Is it because of the anonymous Comparator?

Here is the main class with the serialization

public class Main
{
    public static void main(String args[])
    {
        Central cent = Central.getInstance();
        FileOutputStream fos;
        ObjectOutputStream oos;

        cent.addUser(new Student(3,"id","pass","name","surname"));
        cent.addUser(new Student(3,"id2","pass","name","surname"));
        cent.addUser(new Student(3,"id1","pass","name","surname"));
        try
        {
            fos = new FileOutputStream("save.txt");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(cent);
        }

        catch(IOException e)
        {
            e.printStackTrace();
        }
    }
}
Was it helpful?

Solution

The TreeMap holds a reference to the comparator it uses to compare the keys. And the comparator is an instance of an anonymous class that is not serializable. So you get this exception.

Refactor the anonymous comparator to a top-level, or named inner class, that also implements Serializable.

OTHER TIPS

Another way to force the Comparator to be Serializable is to convert it to lambda with additional bound cast:

TreeMap<Integer, String> sortedMap = new TreeMap<>(
    (Comparator<Integer> & Serializable) (o1, o2) -> {
        return o1.compareTo(o2);
    }
);

Here is the explanation: Java lambda expressions, casting, and Comparators.

Add "implements Serializable" to your Comparator and it should solve the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top