为什么java.io.NotSerializableException:javax.swing.plaf.metal.MetalFileChooserUI?

时间:2011-06-21 21:18:11

标签: java user-interface serialization jfilechooser

我基本上想要在Java中序列化ArrayList,这里显然需要更改代码。 (编辑:粘贴全班)

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


public class GraphEditSerial extends JFrame{

    //stores all dots on the MainPanel
    private ArrayList<Circle> circles = new ArrayList<Circle>();

    class Circle implements Serializable{
        private static final long serialVersionUID = -8364830119753788192L;
        private int x, y;

        public String toString(){
            return "("+x+", "+y+")";
        }

        public Circle(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    //variables for current workmode
    private boolean canInsert = false;
    private boolean canDelete = false;
    private boolean canMove = false;
    private boolean wasMoved = false;

    //defines a JPanel and adds a MouseListener
    class MainPanel extends JPanel implements MouseListener{

        //constructor
        public MainPanel(){
            setBackground(Color.white);
            addMouseListener(this);
        }

        //paints a blue spot on specified location
        public void paint(Graphics g) {
            super.paint(g);
            g.setColor(Color.blue);

            for (Circle k: circles) {
                g.fillOval(k.x - 5, k.y - 5, 10, 10);
            }
        }

        public void mouseClicked(MouseEvent e) {
            //user wants to add a circle
            if(canInsert){
                //adds new circle to ArrayList and displays all circles
                circles.add(new Circle(e.getX(), e.getY()));
                repaint();
            }
            //user wants to delete a circle
            else if(canDelete){
                //checking if clicked position is within 4px of existing circles
                for (int k=0; k<circles.size();k++){
                    Circle c = circles.get(k);
                    if(c.x-e.getX()<=4
                            &&c.x-e.getX()>=-4
                            &&c.y-e.getY()<=4
                            &&c.y-e.getY()>=-4){
                        //removes circle that is within 4 px of clicked position
                        circles.remove(k);
                    }
                }
                repaint();
            }
        }

        //used to move existing circles, but only if current workmode = move
        public void mousePressed(MouseEvent e) {
            //current workmode has to be "move"
            if(canMove==true){
                //checking if clicked position is within 4px of existing circles
                for (int k=0; k<circles.size();k++){
                    Circle c = circles.get(k);
                    if(c.x-e.getX()<=4
                            &&c.x-e.getX()>=-4
                            &&c.y-e.getY()<=4
                            &&c.y-e.getY()>=-4){
                        //removes circle that is within 4 px of clicked position
                        circles.remove(k);
                        wasMoved=true;
                    }
                }
            }
        }

        //displays moved circle at current position of mouse
        public void mouseReleased(MouseEvent e) {
            //current workmode has to be "move"
            if(canMove==true){
                //checking if user clicked on an existing circle before
                if(wasMoved==true){
                    circles.add(new Circle(e.getX(), e.getY()));
                    repaint();
                    wasMoved=false;
                }
            }
        }

        //not assigned
        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}

    }

    //Menu
    JMenuBar mb      = new JMenuBar();
    JMenu graph      = new JMenu("Graph");
    JMenu vertex     = new JMenu("Vertex");
    JMenuItem open   = new JMenuItem("open");
    JMenuItem mnew   = new JMenuItem("new");
    JMenuItem save   = new JMenuItem("save");
    JMenuItem insert = new JMenuItem("insert");
    JMenuItem move   = new JMenuItem("move");
    JMenuItem delete = new JMenuItem("delete");
    JMenuItem none   = new JMenuItem("none");

    //FileChooser
    JFileChooser fc;

    //main panel
    MainPanel main = new MainPanel();

    //bottom row
    JPanel bottomrow = new JPanel(new GridLayout(1,2));
    JLabel l1 = new JLabel("Selected Action:   ", SwingConstants.RIGHT);
    JTextField l2 = new JTextField("none", SwingConstants.LEFT);

    //setting up a Menu with MenuItems, Dimensions, ActionListeners, etc...
    public GraphEditSerial(String s){

        super(s);

        //adding menu items to menus
        graph.add(open);
        graph.add(mnew);
        graph.add(save);
        vertex.add(insert);
        vertex.add(move);
        vertex.add(delete);
        vertex.add(none);

        fc = new JFileChooser();

        //Label l2 changes accordingly to selected MenuItem
        open.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("Graph: open");
                canInsert=false; canDelete=false; canMove=false;
                repaint();

                int returnVal = fc.showOpenDialog(GraphEditSerial.this);
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    File f = fc.getSelectedFile();
                    try{
                        FileInputStream fis = new FileInputStream(f);
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        ArrayList<Circle> a = (ArrayList<Circle>)ois.readObject();
                        circles = a;
                        repaint();
                    }
                    catch (ClassNotFoundException e) {}
                    catch (IOException e){}
                }
            }
        });
        mnew.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("Graph: new");
                canInsert=false; canDelete=false; canMove=false;
                //clears all vertexes
                circles.clear();
                repaint();
            }
        });
        save.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("Graph: save");
                canInsert=false; canDelete=false; canMove=false;
                repaint();

                int returnVal = fc.showSaveDialog(GraphEditSerial.this);
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    String datname = fc.getSelectedFile().getAbsolutePath().toString();
                    try{
                        FileOutputStream fos = new FileOutputStream(datname);
                        ObjectOutputStream oos = new ObjectOutputStream(fos);
                        oos.writeObject((ArrayList<Circle>) circles);
                        oos.close();
                    }
                    catch (IOException e){
                        l2.setText(e.toString());
                        e.printStackTrace();
                    }

                }
            }
        });
        insert.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("Vertex: insert");
                canInsert=true; canDelete=false; canMove=false;
                repaint();
            }

        });
        move.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("Vertex: move");
                canInsert=false; canDelete=false; canMove=true;
                repaint();
            }

        });
        delete.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("Vertex: delete");
                canInsert=false; canDelete=true; canMove=false;
                repaint();
            }

        });
        none.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                l2.setText("none");
                canInsert=false; canDelete=false; canMove=false;
                repaint();
            }

        });

        bottomrow.add(l1);
        bottomrow.add(l2);

        main.setPreferredSize(new Dimension(500,300));
        main.setOpaque(true);
        main.setBackground(Color.WHITE);

        mb.setPreferredSize(new Dimension(500, 20));
        mb.add(graph);
        mb.add(vertex);

        setJMenuBar(mb);
        add(main, BorderLayout.CENTER);
        add(bottomrow, BorderLayout.PAGE_END);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        pack();
        setVisible(true);
        setLocationRelativeTo(null);
    }

    public static void main(String[] arg){
        //new GraphEditor("MyGraphEditor");
        new GraphEditSerial("MyGraphEditor");
    }
}

我是在没有JFileChooser的情况下完成的,只是指定了一个文件名,它就像一个魅力。我也可以毫无问题地反序列化它。但是一旦我使用JFileChooser,我就会得到“java.io.NotSerializableException:javax.swing.plaf.metal.MetalFileChooserUI”

有人有个主意吗?

编辑:这就是e.printStackTrace()打印的内容

java.io.NotSerializableException: javax.swing.plaf.metal.MetalFileChooserUI
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at javax.swing.event.EventListenerList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
at javax.swing.JComponent.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor10.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
at java.awt.Window.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.awt.Window.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at GraphEditSerial$3.actionPerformed(GraphEditSerial.java:202)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.AbstractButton.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

3 个答案:

答案 0 :(得分:1)

Circle是您的UI类本身的内部类吗?如果它是一个内部类,而fc是外部类的一个字段,writeObject元素上的Circle将尝试不仅序列化其字段,而且还序列化其外部类的字段。如果fc是外部类的字段和MetalFileChooserUI,那么它显然会失败序列化。

这是我能从你的代码片段中得出的最佳猜测。如果这不能回答你的问题,vanza说我们需要更多关于Circle的内容的信息

答案 1 :(得分:0)

看起来您正在保存一些附加了此(匿名)ActionListener的对象,或以某种方式引用一个对象,该对象又引用此ActionListener。 ActionListener反过来引用fc对象,即JFileChooser。 JFileChooser本身知道它的UI对象(它执行所有工作,使文件选择器适合您的系统),而且这个不可序列化。

序列化JFileChooser没有意义。它将包含的唯一有趣数据是文件或目录名称,无论如何在其他系统上都无法使用。

一个简单的解决方案是在actionPerformed方法中移动fc,并在那里初始化它(创建一个新的JFileChooser)。

但是你真的想看看为什么你的ActionListener(或它所附加的对象)是序列化的 - 这有时可能很有用,但很可能你不希望你的GUI被序列化,只有数据。要有一些见解,请更改

catch (IOException e){l2.setText(e.toString());}

catch (IOException e){
    l2.setText(e.toString());
    e.printStackTrace();
}

并查看标准输出的堆栈跟踪。它应该显示一个提示尝试序列化的对象。可能是你的圈子有一些他们不应该参考的物体。 (或者是一个应该是暂时的参考。或者当它们不应该是内部类的对象时。)

答案 2 :(得分:0)

我只是想补充一些关于这个问题的其他信息,因为我错过了这个错误(可能是因为我是同一所大学的学生,同一个讲师和完全相同的任务:D)。

在这篇博文中,我详细分析了这个不利的星座:尝试使用处理事件的外部类序列化内部类并使用jfilechooser,但失败了:

http://hannes-schurig.de/21/11/2012/java-problem-beim-serialisieren-von-objekten-bei-der-verwendung-von-ereignishandlern-jfilechooser/

这是德语,但我认为很容易理解这一点,重要的事情是突出的。