FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Linux coco-laptop 2.6.20-16-generic #2 SMP Sun Sep 23 19:50:39 UTC 2007 i686 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
java.io.File has no PersistenceDelegate. Creating a simple one and saving a File directly works normally.
When choosing a File with a JFileChooser, saving this fails; mentioning:
java.lang.InstantiationException: sun.awt.shell.DefaultShellFolder
I do not know the exact location of the failure in code. A test case is given.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a simple File PersistenceDelegate. Verify that saving a file works. Then choose a file from a JFileChooser and try saving that one: this will fail.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Two cases; both have the same PersistenceDelegate set for java.io.File:
When saving a File:
java.lang.InstantiationException: sun.awt.shell.DefaultShellFolder
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(DefaultShellFolder);
Continuing ...
When saving a JavaBean that has a read/write property of type File:
java.lang.InstantiationException: sun.awt.shell.DefaultShellFolder
Continuing ...
java.lang.RuntimeException: failed to evaluate: <unbound>=Class.new();
Continuing ...
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileOutputStream;
import javax.swing.JFileChooser;
import java.beans.Encoder;
import java.beans.Expression;
import java.beans.PersistenceDelegate;
import java.io.IOException;
import java.net.URI;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
public class FilePersistTest2 {
/** Executes 2 XMLEncoder writeObject attempts: one for a File, and one for a FilePersistTest2 bean. */
public static class MyWorker extends SwingWorker<Void, Void> {
private final File file;
public MyWorker(final File file) {
this.file = file;
}
@Override protected Void doInBackground() throws Exception {
Thread.yield();
System.out.println();
System.out.println();
System.out.println();
System.out.println("Saving File: " + file);
save(file);
final FilePersistTest2 filePersistTest2 = new FilePersistTest2();
filePersistTest2.setFile(file);
System.out.println();
System.out.println("Saving JavaBean: " + filePersistTest2);
save(filePersistTest2);
return null;
}
}
private static final PersistenceDelegate filePersistenceDelegate = new PersistenceDelegate() {
@Override
protected Expression instantiate(final Object oldInstance, final Encoder out) {
return new Expression(oldInstance, File.class, "new", new URI[] { ((File) oldInstance).toURI() });
}
};
private static final File staticFile = new File(System.getProperty("user.home"));
private static Class<?> shellFolderClass;
/** Executes 6 XMLEncoder writeObject attempts: the last 2 fail. */
public static void main(final String[] args) throws Exception {
try {
shellFolderClass = Class.forName("sun.awt.shell.DefaultShellFolder");
} catch (final ClassNotFoundException cnfEx) {
System.out.println("Can't get Class for sun.awt.shell.DefaultShellFolder.");
cnfEx.printStackTrace();
System.exit(1);
}
// Save the static file: this works:
(new MyWorker(staticFile)).execute();
// Open a file chooser and then save THE CHOSEN FILE: this does not work:
// Two different errors are produced: one when saving the File directly,
// And one when saving a Bean with a File property:
// Save the static file still works:
final JFrame frame = new JFrame("FilePersistTest2");
final JButton button = new JButton("Choose File...");
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
final JFileChooser chooser = new JFileChooser();
if (chooser.showOpenDialog(frame) != JFileChooser.APPROVE_OPTION) return;
(new MyWorker(staticFile)).execute();
(new MyWorker(chooser.getSelectedFile())).execute();
// The workaround is this: create a new file:
// (new MyWorker(new File(chooser.getSelectedFile().getPath()))).execute();
}
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
/** Each save sets the PersistenceDelegate for java.io.File to the static field in this class. */
private static void save(final Object object) {
XMLEncoder encoder = null;
PersistenceDelegate initialFileDelegate = null;
try {
final File tempFile = File.createTempFile("FilePersistTest2", ".xml");
tempFile.deleteOnExit();
encoder = new XMLEncoder(new FileOutputStream(tempFile));
initialFileDelegate = encoder.getPersistenceDelegate(File.class);
System.out.println("Initial PersistenceDelegate for java.io.File: " + initialFileDelegate);
System.out.println(
"Initial PersistenceDelegate for sun.awt.shell.DefaultShellFolder: "
+ encoder.getPersistenceDelegate(shellFolderClass));
encoder.setPersistenceDelegate(File.class, filePersistenceDelegate);
encoder.writeObject(object);
} catch (final IOException ioEx) {
System.out.println("Caught IOException while saving object.");
ioEx.printStackTrace();
} finally {
if (encoder != null) {
encoder.close();
System.out.println(
"Final PersistenceDelegate for java.io.File: "
+ encoder.getPersistenceDelegate(File.class));
System.out.println(
"Final PersistenceDelegate for sun.awt.shell.DefaultShellFolder: "
+ encoder.getPersistenceDelegate(shellFolderClass));
encoder.setPersistenceDelegate(File.class, initialFileDelegate);
}
}
}
private File file;
public File getFile() { return file; }
public void setFile(final File file) { this.file = file; }
@Override public String toString() { return super.toString() + " [file=" + file + "]"; }
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Instead of saving the CHOSEN File, make a new file using that File's path, and save that one. The instance returned by JFileChooser must be a subclass.