Java unable to serialize a objects which contain TreeMaps with Comparators

让人想犯罪 __ 提交于 2021-02-05 06:48:06

问题


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();
        }
    }
}

回答1:


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.




回答2:


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.




回答3:


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



来源:https://stackoverflow.com/questions/20978922/java-unable-to-serialize-a-objects-which-contain-treemaps-with-comparators

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!