JDK-5086089 : OceanTheme cannot be extended
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,5.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2004-08-12
  • Updated: 2004-11-02
  • Resolved: 2004-10-16
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.
Other JDK 6
5.0u2Fixed 6 b09Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
Name: js151677			Date: 08/12/2004


FULL PRODUCT VERSION :
java version "1.5.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta2-b51)
Java HotSpot(TM) Client VM (build 1.5.0-beta2-b51, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Windows 2000 Professional

EXTRA RELEVANT SYSTEM CONFIGURATION :
No other seemingly-pertinent information available.

A DESCRIPTION OF THE PROBLEM :
The following is a posting to the Java Developer's Forum which I made in an attempt to ascertain that this incident was actually a bug and not my fault.  :)

*****

I started up a project of mine in Java 1.5 today and found that my GUI's L&F had been changed to OceanTheme by default. It looks pretty spiffy, but I'm not fond of the color choices (especially for the desktop background), so I decided to extend OceanTheme and replace many of its primary colors.

I have established the following in Java 1.5:

* Extending the DefaultMetalTheme class causes no problems but changes the appearance of the GUI back to the old Metal design.

* Extending the OceanTheme class is fine with basic components.

* Extending the OceanTheme class and using a JDesktopPane causes no problems either.

* Extending the OceanTheme class, creating a JDesktopPane, putting a JInternalFrame inside of it, and making it visible causes the following to happen:

System.err reports

[code]
ExtensionOfOceanTheme/icons/ocean/maximize.gif not found
ExtensionOfOceanTheme/icons/ocean/maximize-pressed.gif not found
[/code]


Then, I get the following exception:

[code]
Caused by: java.lang.IllegalArgumentException: null delegate icon argument
	at javax.swing.plaf.IconUIResource.<init>(IconUIResource.java:49)
	at javax.swing.plaf.metal.OceanTheme$IFIcon.<init>(OceanTheme.java:77)
	at javax.swing.plaf.metal.OceanTheme$4.createValue(OceanTheme.java:204)
	at javax.swing.UIDefaults.getFromHashtable(UIDefaults.java:183)
	at javax.swing.UIDefaults.get(UIDefaults.java:128)
	at javax.swing.MultiUIDefaults.get(MultiUIDefaults.java:44)
	at javax.swing.UIDefaults.getIcon(UIDefaults.java:409)
	at javax.swing.UIManager.getIcon(UIManager.java:613)
	at javax.swing.plaf.basic.BasicInternalFrameTitlePane.installDefaults(BasicInternalFrameTitlePane.java:148)
	at javax.swing.plaf.metal.MetalInternalFrameTitlePane.installDefaults(MetalInternalFrameTitlePane.java:94)
	at javax.swing.plaf.basic.BasicInternalFrameTitlePane.installTitlePane(BasicInternalFrameTitlePane.java:97)
	at javax.swing.plaf.basic.BasicInternalFrameTitlePane.<init>(BasicInternalFrameTitlePane.java:93)
	at javax.swing.plaf.metal.MetalInternalFrameTitlePane.<init>(MetalInternalFrameTitlePane.java:81)
	at javax.swing.plaf.metal.MetalInternalFrameUI.createNorthPane(MetalInternalFrameUI.java:120)
	at javax.swing.plaf.basic.BasicInternalFrameUI.installComponents(BasicInternalFrameUI.java:171)
	at javax.swing.plaf.basic.BasicInternalFrameUI.installUI(BasicInternalFrameUI.java:88)
	at javax.swing.plaf.metal.MetalInternalFrameUI.installUI(MetalInternalFrameUI.java:54)
	at javax.swing.JComponent.setUI(JComponent.java:650)
	at javax.swing.JInternalFrame.setUI(JInternalFrame.java:326)
	at javax.swing.JInternalFrame.updateUI(JInternalFrame.java:342)
	at javax.swing.JInternalFrame.<init>(JInternalFrame.java:290)
	at javax.swing.JInternalFrame.<init>(JInternalFrame.java:207)
[/code]


I've traced this execution path about and found that the resource manager is actually returning null for the two resources (maximize.gif and maximize-pressed.gif). My first thought was that those images are not in the JDK's resource kit, but the OceanTheme class itself works fine. I believe there may be a security/permissions sort of problem here... the extended class is not being permitted to access the GIF resource.

Can anyone confirm my beliefs here so I can report this as a bug?

Thanks!

REGRESSION.  Last worked in version tiger-beta2

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the following code:

[code]
MetalLookAndFeel.setCurrentTheme(new OceanTheme());
UIManager.setLookAndFeel(new MetalLookAndFeel());
[/code]

Then display a JInternalFrame.  Nothing will go wrong.

Then, execute this code:

[code]
MetalLookAndFeel.setCurrentTheme(new OceanTheme()
{
});
UIManager.setLookAndFeel(new MetalLookAndFeel());
[/code]

It should doubtlessly run the same.  However, when a JInternalFrame is displayed, the previously described error will occur.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected the two segments of code as described above to behave in the same fashion.
ACTUAL -
The case in which new OceanTheme(){} is used creates an anonymous class.  This extension of OceanTheme cannot retrieve "maximize.gif" from the system resources and the JInternalFrame is never rendered.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
On System.err:

ExtensionOfOceanTheme/icons/ocean/maximize.gif not found
ExtensionOfOceanTheme/icons/ocean/maximize-pressed.gif not found

Caught as an exception:

Caused by: java.lang.IllegalArgumentException: null delegate icon argument
	at javax.swing.plaf.IconUIResource.<init>(IconUIResource.java:49)
	at javax.swing.plaf.metal.OceanTheme$IFIcon.<init>(OceanTheme.java:77)
	at javax.swing.plaf.metal.OceanTheme$4.createValue(OceanTheme.java:204)
	at javax.swing.UIDefaults.getFromHashtable(UIDefaults.java:183)
	at javax.swing.UIDefaults.get(UIDefaults.java:128)
	at javax.swing.MultiUIDefaults.get(MultiUIDefaults.java:44)
	at javax.swing.UIDefaults.getIcon(UIDefaults.java:409)
	at javax.swing.UIManager.getIcon(UIManager.java:613)
	at javax.swing.plaf.basic.BasicInternalFrameTitlePane.installDefaults(BasicInternalFrameTitlePane.java:148)
	at javax.swing.plaf.metal.MetalInternalFrameTitlePane.installDefaults(MetalInternalFrameTitlePane.java:94)
	at javax.swing.plaf.basic.BasicInternalFrameTitlePane.installTitlePane(BasicInternalFrameTitlePane.java:97)
	at javax.swing.plaf.basic.BasicInternalFrameTitlePane.<init>(BasicInternalFrameTitlePane.java:93)
	at javax.swing.plaf.metal.MetalInternalFrameTitlePane.<init>(MetalInternalFrameTitlePane.java:81)
	at javax.swing.plaf.metal.MetalInternalFrameUI.createNorthPane(MetalInternalFrameUI.java:120)
	at javax.swing.plaf.basic.BasicInternalFrameUI.installComponents(BasicInternalFrameUI.java:171)
	at javax.swing.plaf.basic.BasicInternalFrameUI.installUI(BasicInternalFrameUI.java:88)
	at javax.swing.plaf.metal.MetalInternalFrameUI.installUI(MetalInternalFrameUI.java:54)
	at javax.swing.JComponent.setUI(JComponent.java:650)
	at javax.swing.JInternalFrame.setUI(JInternalFrame.java:326)
	at javax.swing.JInternalFrame.updateUI(JInternalFrame.java:342)
	at javax.swing.JInternalFrame.<init>(JInternalFrame.java:290)
	at javax.swing.JInternalFrame.<init>(JInternalFrame.java:207)




REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
    public static void oceanThemeBugDemo()
            throws Exception
    {
        final JFrame f = new JFrame();
        JDesktopPane d = new JDesktopPane();
        JScrollPane s = new JScrollPane(d);
        s.setPreferredSize(new Dimension(400,300));
        f.setContentPane(s);
        JInternalFrame jif = new JInternalFrame();
        jif.getContentPane().add(new JLabel("test"));
        jif.pack();
        jif.setVisible(true);
        jif.setResizable(true);
        d.add(jif);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);

        final JFrame ctl = new JFrame("Controls");
        Container c = ctl.getContentPane();
        c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS));
        JButton b = new JButton("Metal - Steel");
        c.add(b);
        b.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
                try
                {
                    UIManager.setLookAndFeel(new MetalLookAndFeel());
                } catch (UnsupportedLookAndFeelException e1)
                {
                    e1.printStackTrace();
                }
                SwingUtilities.updateComponentTreeUI(f);
                SwingUtilities.updateComponentTreeUI(ctl);
            }
        });
        b = new JButton("Metal - Ocean");
        c.add(b);
        b.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                MetalLookAndFeel.setCurrentTheme(new OceanTheme());
                try
                {
                    UIManager.setLookAndFeel(new MetalLookAndFeel());
                } catch (UnsupportedLookAndFeelException e1)
                {
                    e1.printStackTrace();
                }
                SwingUtilities.updateComponentTreeUI(f);
                SwingUtilities.updateComponentTreeUI(ctl);
            }
        });
        b = new JButton("Metal - Ocean Extended");
        c.add(b);
        b.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                MetalLookAndFeel.setCurrentTheme(new OceanTheme()
                {
                });
                try
                {
                    UIManager.setLookAndFeel(new MetalLookAndFeel());
                } catch (UnsupportedLookAndFeelException e1)
                {
                    e1.printStackTrace();
                }
                SwingUtilities.updateComponentTreeUI(f);
                SwingUtilities.updateComponentTreeUI(ctl);
            }
        });
        ctl.pack();
        ctl.setLocationRelativeTo(f);
        ctl.setVisible(true);

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ctl.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Don't extend OceanTheme.
(Incident Review ID: 296712) 
======================================================================
###@###.### 10/12/04 17:23 GMT

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: dragon mustang FIXED IN: mustang
29-09-2004

EVALUATION Needs to be investigated further. ###@###.### 2004-08-12 The problem here lies in how Ocean fetches icon images from the file system. It uses LookAndFeel.makeIcon with getClass(), which in turn uses getResourceAsStream() based on that class. The problem with this is that when Ocean is extended, getClass() returns that subclass and the icon images can't be found using getResourceAsStream() on that class. What needs to happen is for the search for icon files to START at the current class (for extensibility), but then continue by checking relative to the superclass, and then it's superclass, etc. up to and including Ocean. A new non-public method has been added to encapsulate this behavior. LookAndFeel.makeIcon will continue to do what it always did, but Ocean will directly call the new method. Additionally, I've noticed that BasicLookAndFeel, MotifLookAndFeel, and WindowsLookAndFeel also use LookAndFeel.makeIcon and therefore would exhibit the same problems if extended. They've also been changed to use the new method. ###@###.### 2004-09-22
22-09-2004