JDK-4905329 : Cannot serialize JButton that was configured from an Action
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.1,1.4.1,1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt,windows_xp
  • CPU: x86
  • Submitted: 2003-08-12
  • Updated: 2005-08-11
  • Resolved: 2005-08-11
Related Reports
Duplicate :  
Relates :  
Description
Name: jk109818			Date: 08/12/2003


FULL PRODUCT VERSION :


A DESCRIPTION OF THE PROBLEM :
When a JButton, created through the constructor that takes a single Action argument, is passed to ObjectOutputStream.writeObject, a NotSerializableException is thrown.

It seems that the field actionPropertyChangeListener should be declared transient or that the class javax.swing.AbstractActionPropertyChangeListener should be serializable (probably the former).

This is illustrated by the following piece of code:

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

class Test2 implements Serializable {

	private JFrame frame = new JFrame();

	private JButton button = new JButton(new AbstractAction("Save & Exit") {
		public void actionPerformed(ActionEvent _) {
			try {
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("saved"));
				oos.writeObject(button);
				oos.close();
			} catch (Exception e) {
				System.out.println(e);
			}
			System.exit(1);
		}
	});

	Test2() {
		frame.getContentPane().add(button);
		frame.pack();
		frame.setVisible(true);
	}

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


ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.NotSerializableException: javax.swing.AbstractButton$ButtonActionPropertyChangeListener

REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
Use a constructor for the JButton not based on an Action and manually set a listener on it. This solution is not acceptable to us however as we have other issues involving buttons/actions. The workaround is illustrated with the code below:

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

class Test2 implements Serializable {

	private JFrame frame = new JFrame();

	private JButton button = new JButton("Save & Exit");

	protected ActionListener actionListener = new ActionListener() {
		public void actionPerformed(ActionEvent _) {
			try {
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("saved"));
				oos.writeObject(button);
				oos.close();
			} catch (Exception e) {
				System.out.println(e);
			}

			System.exit(1);
		}
	};

	Test2() {
		frame.getContentPane().add(button);
		frame.pack();
		frame.setVisible(true);

		button.addActionListener(actionListener);
	}

	public static void main(String[] args) {
		new Test2();
	}
}
(Incident Review ID: 186247) 
======================================================================

Comments
EVALUATION The test case now passes and appears to have been addressed by 4966168. But if you dig a bit deeper you'll see that while the exception no longer occurs, the test doesn't really work. In fact you can serialize ok now, but deserializing doesn't work. The fix for 4966168 made the internal listener class serializable, but this didn't address the problem. I've fixed this as part of 4626632, refer to it for details.
11-08-2005

EVALUATION This bug still exists. Customer suggestions are valid. You may want to use the XMLEncoder/XMLDecoder for long term serialization.
25-09-2004