开发者

Why java.io.NotSerializableException: javax.swing.plaf.metal.MetalFileChooserUI?

I basically want to serialize an ArrayList in Java, and here is the code that apparently needs to be changed. (EDIT: pasted entire class)

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();
            开发者_如何学C        }
                    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");
    }
}

I did it without the JFileChooser and just specified a filename, and it worked like a charm. I could also deserialize it without problems. But as soon as I use JFileChooser, I get "java.io.NotSerializableException: javax.swing.plaf.metal.MetalFileChooserUI"

Anyone got an idea?

EDIT: this is what e.printStackTrace() prints

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)


Is Circle an inner class of your UI class itself? If it is an inner class and fc is a field of the outer class the writeObject on a Circle element will try to serialize not only its fields but its outer-class's fields too. And if fc is a field of the outer-class and a MetalFileChooserUI then it will obviously fail serialization.

That's the best guess I can come up with from your code snippet. If that doesn't answer your question, as vanza says we would need more information on the content of the Circle


It looks like you are saving some object which has this (anonymous) ActionListener attached, or somehow references an object which in turn references this ActionListener. The ActionListener, in turn references the fc object, which is a JFileChooser. The JFileChooser itself knows its UI object (which does all the work such that the file chooser fits in your system), and this one is not serializable.

There is no point in serializing a JFileChooser. The only interesting data it would contain are the file or directory name, which anyway could be unusable on another system.

An easy solution would be moving the fc inside the actionPerformed method, and initialize it there (creating a new JFileChooser).

But you really want to have a look why your ActionListener (or the object it is attached to) is serialized - this sometimes could be useful, but most probably you don't want your GUI to be serialized at all, only the data. To have some insight, change

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

to

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

and look at the stack trace from standard output. It should show you a hint which objects are tried to serialize. It could be that your Circles have a reference to some object which they shouldn't, really. (Or a reference which should be transient. Or that they are objects of an inner class when they should not.)


I just wanted to add some additional information about that problem because I ran over exactly this error (probably because I am a student at the same university with the same lecturer and the exact same task :D).

In this blogpost I analysed this adverse constellation in detail: try to serialize an inner class with an outer class that handles events and uses jfilechooser, which fails:

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

It's in german but I think it's easy to get the point, important things are highlighted.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜