0

When trying to save an arraylist of my class Click, I get this error: java.io.NotSerializableException:javax.swing.text.DefaultHighlighter$LayeredHighlightInfo on this line of code: os.writeObject(saveList);. Even though I made my Click class implement serializable. Does anyone know the cause of this?

Here is my save Method:

public static void saveArray(ArrayList<Click> saveList) {
        JFileChooser c = new JFileChooser();
        c.showSaveDialog(new JFrame());
        File f = c.getSelectedFile();
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
                                f.getAbsolutePath()));
            os.writeObject(saveList);
        } catch (IOException e1) {
        e1.printStackTrace();
    }
}

And here is my Click class:

public static class Click implements Serializable {
    JTextField xClickField;
    JTextField yClickField;
    JTextField clickIntervalField;
    JTextField repeatTimesField;
    boolean isLeft;
    Integer clickX;
    Integer clickY;
    Integer clickInterval;
    Integer clickTimes;

    public Click(boolean left){
        xClickField = new JTextField();
        yClickField = new JTextField();
        clickIntervalField = new JTextField();
        repeatTimesField = new JTextField();
        clickX = 0;
        clickY = 0;
        clickInterval = 0;
        clickTimes = 0;
        isLeft = left;
        addToJPanel();
    }

    public void addToJPanel() {
        xClickField.setText(clickX.toString());
        yClickField.setText(clickY.toString());
        clickIntervalField.setText(clickInterval.toString());
        repeatTimesField.setText(clickTimes.toString());
        panel.add(xClickField);
        panel.add(yClickField);
        panel.add(clickIntervalField);
        panel.add(repeatTimesField);

        frame.setVisible(false);
        frame.setVisible(true);
    }

    public void removeFromJPanel() {
        panel.remove(xClickField);
        panel.remove(yClickField);
        panel.remove(clickIntervalField);
        panel.remove(repeatTimesField);

        frame.setVisible(false);
        frame.setVisible(true);
    }
}

By the way I took out a chunk of code from the Click class. So if you think that the error could be in that portion of the code, I will gladly add it in.

Thanks in advance!

7
  • 2
    The error tells you exactly which component of Click is not serializing correctly, but more importantly -- why would you want to serialize Swing components rather than the logical model that underlies your GUI? This doesn't make sense to me. Commented Jun 30, 2012 at 17:05
  • it's the jtextfield thats's not serializing correctly? And what do you mean with "the logical model that underlies your Gui?" Commented Jun 30, 2012 at 17:08
  • You're serializing JTextFields and other Swing components which is a waste of time and resources and is completely unnecessary. You should be serializing the state of your GUI, the data held by the class's fields. If you understand MVC, you should be serializing the model, not the view. If you don't understand MVC, Google it and learn the key concepts as they are key to creating GUI programs in any language. Commented Jun 30, 2012 at 17:10
  • which version of java are you using? highlighter object in JTextComponent is transient in both java 6 and 7. Anyways, everybody else is right, serializing swing components is useless and is probably wrong. Commented Jun 30, 2012 at 17:21
  • ok I looked up MVC - model view controller, right? Ok and I got what it said. I should save the data, or in this case, the int values in the JTextFields, instead of saving the JTextField. Commented Jun 30, 2012 at 17:22

4 Answers 4

2

Implementing Serializable is not sufficient to make an object serializable. For example, a Socket is not serializable: it doesn't make sense to serialize a socket. So, if you have a Foo class that has a field of type Socket and that implements Serializable, how do you intend to serialize a Foo instance. It won't work. All the fields of a serializable object msut also be serializable, recursively.

And, as Hovercraft says in his comment, you should serialize data, not swing components.

Sign up to request clarification or add additional context in comments.

Comments

2

You're serializing JTextFields and other Swing components which is a waste of time and resources and is completely unnecessary. You should be serializing the state of your GUI, the data held by the class's fields. If you understand MVC, you should be serializing the model, not the view. If you don't understand MVC, Google it or read this article and learn the key concepts as they are key to creating GUI programs in any language.

Also, for my money, I'd use JAXB or some other XML-based tool to serialize your data as it is saved in text format and thus understandable when read.

Example of separating GUI from model and using a property change listener to listen and respond to property changes:

import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;

import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;

public class SimpleClickEg {
   private static void createAndShowGui() {
      SimpleClickPanel clickPanel = new SimpleClickPanel();

      JFrame frame = new JFrame("SimpleClickEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(clickPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class SimpleClickPanel extends JPanel {
   private static final int PREF_WIDTH = 800;
   private static final int PREF_HIEGHT = 600;
   private JTextField clickCountField = new JTextField(5);
   private JTextField clickXField = new JTextField(5);
   private JTextField clickYField = new JTextField(5);
   private SimpleClick click = new SimpleClick();

   public SimpleClickPanel() {
      add(new JLabel("Click X:"));
      add(clickXField);
      add(new JLabel("Click Y:"));
      add(clickYField);
      add(new JLabel("Click Count:"));
      add(clickCountField);

      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent e) {
            click.setClickPoint(e.getPoint());
         }
      });

      click.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if (SimpleClick.CLICK_COUNT.equals(evt.getPropertyName())) {
               clickCountField.setText(String.valueOf(click.getClickCount()));
            } else if (SimpleClick.CLICK_X.equals(evt.getPropertyName())) {
               clickXField.setText(String.valueOf(click.getClickX()));
            } else if (SimpleClick.CLICK_Y.equals(evt.getPropertyName())) {
               clickYField.setText(String.valueOf(click.getClickY()));
            }
         }
      });
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_WIDTH, PREF_HIEGHT);
   }

   public SimpleClick getClick() {
      return click;
   }
}

class SimpleClick implements Serializable {
   private static final long serialVersionUID = 1L;
   public static final String CLICK_COUNT = "click count";
   public static final String CLICK_X = "click x";
   public static final String CLICK_Y = "click y";

   private int clickCount;
   private int clickX;
   private int clickY;
   private transient SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
         this);

   public int getClickCount() {
      return clickCount;
   }

   public void setClickCount(int clickCount) {
      Integer oldValue = this.clickCount;
      Integer newValue = clickCount;
      this.clickCount = newValue;
      spcSupport.firePropertyChange(CLICK_COUNT, oldValue, newValue);
   }

   public void incrementClickCount() {
      setClickCount(getClickCount() + 1);
   }

   public void setClickPoint(Point p) {
      setClickX(p.x);
      setClickY(p.y);
      incrementClickCount();
   }

   public int getClickX() {
      return clickX;
   }

   public void setClickX(int clickX) {
      Integer oldValue = this.clickX;
      Integer newValue = clickX;
      this.clickX = newValue;
      spcSupport.firePropertyChange(CLICK_X, oldValue, newValue);
   }

   public int getClickY() {
      return clickY;
   }

   public void setClickY(int clickY) {
      Integer oldValue = this.clickY;
      Integer newValue = clickY;
      this.clickY = newValue;
      spcSupport.firePropertyChange(CLICK_Y, oldValue, newValue);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      spcSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      spcSupport.removePropertyChangeListener(listener);
   }

}

Comments

1

As you can see the error clearly states that javax.swing.text.DefaultHighlighter is not serializable.

Now this class is used by composition inside the JTextField, which is a GUI component and it is not meant to be serialized. From your code it seems that you don't need to serialize the fields themselves, so just mark them as transient and you are done.

As a side note: it is always good to split what is your data from what is your GUI so that you can easily serialize just data and foget about anything concerning the GUI. This helps in general, not just in serialization, to preserve encapsulation and use OOP as it is meant to be used.

Comments

1

The problem is that your Click class has references to JTextField instances, and these (presumably) have references to some Swing class called DefaultHighlighter.LayeredHighlightInfo ... and that is not serializable.

You probably need to declare the 4 JTextField variables as transient. As a general rule, Java GUI classes such as Swing components are not effectively serializable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.