سؤال

I am writing an application in Java and part of what it needs to do is serialize some objects so they can be imported later. When I wrote the serialization code, it did not work correctly. After much tinkering, I believe I have narrowed it down to only a few attributes and included the minimum possible code to trigger the error in this SSCEE:

import java.io.*;
import java.util.prefs.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;

//main class
public class SerializeFail extends JFrame implements Serializable, ActionListener {
    JMenuBar bar = new JMenuBar();
    JMenu file = new JMenu("File");
    JMenuItem item = new JMenuItem("Click to Fail");

    HashMap<String, Preferences> prefs = new HashMap<String, Preferences>();    
    public SerializeFail () {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        file.add(item);
        bar.add(file);
        item.addActionListener(this);
        prefs.put("root", Preferences.userRoot().node(this.getClass().getName()));
        setJMenuBar(bar);
        pack();
        setVisible(true);
    }

    //triggers the failure
    public void actionPerformed (ActionEvent e) {
        TestObject gr = new TestObject();
        try {
            FileOutputStream fileOutput = new FileOutputStream("testing.gradecalc");
            ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
            objectOutput.writeObject(gr);
            fileOutput.close();
            System.out.println("serialized");
        } catch (FileNotFoundException fileNotFound) {
            System.out.println("The file was not found");
            fileNotFound.printStackTrace();
        } catch (IOException io) {
            System.out.println("There was some type of io exception");
            System.out.println("Stack Trace");
            io.printStackTrace();
            System.out.println("Message Trace");
            io.getMessage();
            System.out.println("Cause Trace");
            io.getCause();
        }
    }


    public static void main(String[] args) {
        new SerializeFail();
    }

    class TestObject implements Serializable {
        int attribute;
        public TestObject () {
            attribute = 47;
        }
    }
}

The error I get's stack trace is:

There was some type of io exception
Stack Trace
java.io.NotSerializableException: com.apple.laf.AquaMenuBarBorder
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1181)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:439)
    at javax.swing.JComponent.writeObject(JComponent.java:5525)
    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:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1375)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1171)
    at java.io.ObjectOutputStream.access$300(ObjectOutputStream.java:162)
    at java.io.ObjectOutputStream$PutFieldImpl.writeFields(ObjectOutputStream.java:1700)
    at java.io.ObjectOutputStream.writeFields(ObjectOutputStream.java:479)
    at java.awt.Container.writeObject(Container.java:3681)
    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:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1375)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1171)
    at java.io.ObjectOutputStream.access$300(ObjectOutputStream.java:162)
    at java.io.ObjectOutputStream$PutFieldImpl.writeFields(ObjectOutputStream.java:1700)
    at java.io.ObjectOutputStream.writeFields(ObjectOutputStream.java:479)
    at java.awt.Container.writeObject(Container.java:3681)
    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:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1506)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at java.awt.AWTEventMulticaster.save(AWTEventMulticaster.java:946)
    at java.awt.Component.writeObject(Component.java:8645)
    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)
Message Trace
Cause Trace
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1506)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at SerializeFail.actionPerformed(SerializeFail.java:34)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.AbstractButton.doClick(AbstractButton.java:376)
    at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:833)
    at com.apple.laf.AquaMenuItemUI.doClick(AquaMenuItemUI.java:157)
    at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:877)
    at java.awt.Component.processMouseEvent(Component.java:6505)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
    at java.awt.Component.processEvent(Component.java:6270)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4861)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
    at java.awt.Container.dispatchEventImpl(Container.java:2273)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:708)
    at java.awt.EventQueue$4.run(EventQueue.java:706)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

On an interesting note, if the graphics related objects are eliminated such that the SSCEE is:

import java.io.*;
import java.util.prefs.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;

//main class
public class SerializeFail implements Serializable {
    HashMap<String, Preferences> prefs = new HashMap<String, Preferences>();    
    public SerializeFail () {
        prefs.put("root", Preferences.userRoot().node(this.getClass().getName()));
        TestObject gr = new TestObject();
        try {
            FileOutputStream fileOutput = new FileOutputStream("testing.gradecalc");
            ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
            objectOutput.writeObject(gr);
            fileOutput.close();
            System.out.println("serialized");
        } catch (FileNotFoundException fileNotFound) {
            System.out.println("The file was not found");
            fileNotFound.printStackTrace();
        } catch (IOException io) {
            System.out.println("There was some type of io exception");
            System.out.println("Stack Trace");
            io.printStackTrace();
            System.out.println("Message Trace");
            io.getMessage();
            System.out.println("Cause Trace");
            io.getCause();
        }
    }


    public static void main(String[] args) {
        new SerializeFail();
    }

    class TestObject implements Serializable {
        int attribute;
        public TestObject () {
            attribute = 47;
        }
    }
}

then the output (containing the stack trace of the exception) is:

There was some type of io exception
Stack Tracejava.io.NotSerializableException: java.util.prefs.MacOSXPreferences
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1181)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at java.util.HashMap.writeObject(HashMap.java:1100)
    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:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1506)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1506)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at SerializeFail.<init>(SerializeFail.java:16)
    at SerializeFail.main(SerializeFail.java:35)
Message Trace
Cause Trace

I have looked around and researched serialization, but to no avail. Could someone please make it so the instance of TestObject serializes without fail with the graphics related components (first SSCEE) included because that is what the master application has (or at least point me in the right direction)?

Thank you. If there is anything else I can provide that would be of assistance, please just ask.

هل كانت مفيدة؟

المحلول

All of your non-static fields have to be either transient or transitively Serializable for the default serializer to work. In your case, the Apple look-and-feel and MacOSXPreferences, which are referenced by the fields you declare directly, aren't serializable.

Oddly enough, even though the Swing components all implement Serializable, the actual runtime implementations don't, and making Swing stuff Serializable is widely regarded to have been a mistake. Instead, you need to encapsulate the state (model) separately from the UI (view/controller). Serialize just the model object and have your client code rebuild the UI and then populate it from the saved model.

Similarly, Preferences is not Serializable, and so the runtime can't use default serialization for it. How you handle serializing the preferences depends on what you're trying to do; it's not clear from your example.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top