JDK-6372808 : JFileChooser takes a long time to instantiate, at least the first time
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.5.1,6
  • Priority: P2
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2006-01-16
  • Updated: 2011-02-22
  • Resolved: 2009-08-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7Resolved
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-rc-b66)
Java HotSpot(TM) Client VM (build 1.6.0-rc-b66, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600] (with sp2)

A DESCRIPTION OF THE PROBLEM :
The JFileChooser is very slow to open (towards 10 seconds), at least the first time. Subsequent instantiations and navigation of the GUI are in some cases faster, and other cases not.

As suggested in bug 6317789, I tried setting "useShellFolder" to False, as in:
putClientProperty("FileChooser.useShellFolder", Boolean.FALSE);

This made the dialog appear "instantly", and all browsing is pretty much instant, with file sizes and all, but without the elaborate windows GUI.

Using JProfiler under the opening sequence, I found the following:
87.1% of the time used is in the JFileChooser.<init>. This is again broken down to 48.9% in .setup(), and 38.2% in .setCurrentDirectory(). These again both boil down through the following chain:
  sun.awt.shell.ShellFolder.get
  sun.awt.shell.Win32ShellFolderManager2.get
  sun.awt.shell.Win32ShellFolder2.isDirectory
  sun.awt.shell.Win32ShellFolder2.hasAttribute
  sun.awt.shell.Win32ShellFolder2.getAttributes0()
.. with 35.3.% and 34.1% respectively. Thus, ~70% of the time is spent in this one method.

This happens both on the jdk 1.5 (cutting edge), and now also on the latest snapshot of 1.6.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Check out the attached source. This might not be a fantastic way to code, but it demonstrates some weirdness I at least experience consistently on my setup.

The three booleans will controll different "bug-aspects":
  _fixChooser sets the useShellFolder to false
  _windowsLookAndFeel sets the windows look and feel (giving the "elaborate" FileChooser)
  _makeChooserInMain simply instantiates a JFileChooser in the main thread, and does nothing else with it.

If _fixChooser is true, the whole "application" is fast, both instantiations of JFileChooser and navigations of it, regardless of the other two booleans.

If _fixChooser is false, then both instantiations and navigation is very slow unless _makeChooserInMain is true. This is what I find very puzzling: if you make a JFileChooser in main before the main thread exits, then this will delay the startup by 7-8 seconds, but subsequent instantiations of the JFileChooser and all navigation is very fast.

The _windowsLookAndFeel does not affect the speed aspect at all.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Fast instantiation and GUI-navigation of the JFileChooser
ACTUAL -
Unusable slow, always in the first instantiation, and in certain circumstances for every "move" within the GUI and all subsequent instantiations.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;

public class Test2 {

	static boolean _fixChooser = false;

	static boolean _windowsLookAndFeek = true;

	static boolean _makeChooserInMain = true;

	public static void main(String[] args) throws InterruptedException {
		System.out.println("start");
		if (_windowsLookAndFeek) {
			try {
				UIManager.setLookAndFeel(new com.sun.java.swing.plaf.windows.WindowsLookAndFeel());
			}
			catch (UnsupportedLookAndFeelException e) {
				e.printStackTrace();
			}
		}
		if (_makeChooserInMain) {
			getJFileChooser();
		}
		MyFrame myFrame = new MyFrame();
		myFrame.startUp();
		System.out.println("leaving main.");
	}

	static JFileChooser getJFileChooser() {
		long startTime = System.currentTimeMillis();
		System.out.println(Thread.currentThread() + " :: Before new JFileChooser()");
		JFileChooser ret;
		if (_fixChooser) {
			ret = new JFileChooser() {
				private static final long serialVersionUID = 1541813407103968847L;

				@Override
				public void updateUI() {
					putClientProperty("FileChooser.useShellFolder", Boolean.FALSE);
					super.updateUI();
				}
			};
		}
		else {
			ret = new JFileChooser();
		}
		System.out.println(Thread.currentThread() + " :: After new JFileChooser(), took ["
				+ (System.currentTimeMillis() - startTime) + "].");
		return ret;
	}

	public static class MyFrame extends JFrame {
		public void startUp() {
			setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					build();
					setSize(new Dimension(100, 100));
					setVisible(true);
				}
			});
		}

		public void build() {
			Container contentPane = getContentPane();
			JButton launchChooser = new JButton("launch chooser");
			launchChooser.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getJFileChooser().showDialog(null, "test!");
					System.out.println(".showDialog exited.");
				}
			});
			contentPane.add(launchChooser);
		}
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Make a JFileChooser instance in the main thread (which gives a one-time impact), or set the useShellFolder to false.

Comments
EVALUATION It seems this bug is a duplicate of CR 5050516. I can't reproduce the bug with current build and with old builds. As I see from the description the stacktrace contains the next lines: sun.awt.shell.Win32ShellFolder2.isDirectory sun.awt.shell.Win32ShellFolder2.hasAttribute Actually the fix of CR 5050516 fixes the problem in the isDirectory() method: one invocation of the hasAttribute() method was removed and that invocation took a lot of time on ZIP files.
24-08-2009

EVALUATION Nelson informed me that the issue was actually investigated by Endre Stolsvik, a customer and the author of initial incident, so I would like to say: Thank you Endre!
26-10-2006

EVALUATION The method sun.awt.shell.Win32ShellFolder2.getAttributes0() should be further profiled and the bottleneck should be eliminated. Thanks to Nelson, the originator of this CR, for his excellent investigation.
23-01-2006