Почему java.io.NotSerializableException: javax.swing.plaf.metal.MetalFileChooserUI? - PullRequest
0 голосов
/ 22 июня 2011

Я в основном хочу сериализовать ArrayList в Java, и вот код, который, по-видимому, необходимо изменить. (РЕДАКТИРОВАТЬ: вставил весь класс)

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 ]

1 голос
/ 22 июня 2011

Является ли Circle внутренним классом самого вашего класса пользовательского интерфейса? Если это внутренний класс, а fc - поле внешнего класса, writeObject в элементе Circle попытается сериализовать не только его поля, но и поля его внешнего класса. И если fc является полем внешнего класса и MetalFileChooserUI, то он, очевидно, не сможет сериализоваться.

Это лучшее предположение, которое я могу придумать из вашего фрагмента кода. Если это не отвечает на ваш вопрос, как говорит Ванза, нам нужно больше информации о содержании Circle

0 голосов
/ 21 ноября 2012

Я просто хотел добавить дополнительную информацию об этой проблеме, потому что я столкнулся именно с этой ошибкой (возможно, потому что я учусь в том же университете с тем же преподавателем и той же задачей: D).

В этом посте я подробно проанализировал это неблагоприятное созвездие: попробуйте сериализовать внутренний класс с внешним классом, который обрабатывает события и использует jfilechooser, который завершается ошибкой:

http://hannes -schurig.de / 21/11/2012 / Java-проблемно-байм-serialisieren-фон-Objekten-бей-дер-verwendung-фон-ereignishandlern-JFileChooser /

Это по-немецки, но я думаю, что это легко понять, важные вещи выделены.

0 голосов
/ 22 июня 2011

Похоже, что вы сохраняете некоторый объект, к которому прикреплен этот (анонимный) ActionListener, или каким-то образом ссылаетесь на объект, который в свою очередь ссылается на этот ActionListener. ActionListener, в свою очередь, ссылается на объект fc, который является JFileChooser. JFileChooser сам знает свой объект пользовательского интерфейса (который выполняет всю работу таким образом, что средство выбора файлов вписывается в вашу систему), и этот объект не сериализуем.

Нет смысла сериализовать JFileChooser. Единственные интересные данные, которые он содержит, - это имя файла или каталога, которые в любом случае могут быть непригодны для использования в другой системе.

Простым решением было бы переместить fc в метод actionPerformed и инициализировать его там (создав новый JFileChooser).

Но вы действительно хотите узнать, почему ваш ActionListener (или объект, к которому он присоединен) сериализован - это иногда может быть полезно, но, скорее всего, вы не хотите, чтобы ваш графический интерфейс вообще сериализовался, только данные. Чтобы иметь представление, измените

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

до

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

и посмотрите на трассировку стека из стандартного вывода. Он должен показать вам подсказку, какие объекты пытаются сериализовать. Может случиться так, что ваши Круги имеют ссылку на какой-то объект, который на самом деле не должен. (Или ссылка, которая должна быть кратковременной. Или что они являются объектами внутреннего класса, когда они не должны.)

...