JDK-6625661 : updateUI causes StackOverflowError in JTableHeaders that are their own renderers
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-11-03
  • Updated: 2010-04-04
  • Resolved: 2007-11-06
Related Reports
Duplicate :  
Description
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 :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
A JTableHeader that implements TableCellRenderer and is set as its own DefaultRenderer will cause a StackOverFlowError in updateUI().
This is caused by
        TableCellRenderer renderer = getDefaultRenderer();
        if (!(renderer instanceof UIResource) && renderer instanceof Component) {
            SwingUtilities.updateComponentTreeUI((Component)renderer);
        }
in JTableHeader.java. updateComponentTreeUI calls updateUI and this leads to infinite recursion in the described situation.
The above code should be changed to
TableCellRenderer renderer = getDefaultRenderer();
        if (renderer != this && !(renderer instanceof UIResource) && renderer instanceof Component) {
            SwingUtilities.updateComponentTreeUI((Component)renderer);
        }

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Write a JTableHeader that implements TableCellRenderer. Create an instance head. Call head.setDefaultRenderer(head). Call updateUI().

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
no error
ACTUAL -
StackOverflowError

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.StackOverflowError
        at java.awt.Container.findComponentAtImpl(Container.java:2498)
        at java.awt.Container.findComponentAtImpl(Container.java:2528)
        at java.awt.Container.findComponentAtImpl(Container.java:2528)
        at java.awt.Container.findComponentAtImpl(Container.java:2528)
        at java.awt.Container.findComponentAtImpl(Container.java:2528)
        at java.awt.Container.findComponentAt(Container.java:2492)
        at sun.awt.windows.WGlobalCursorManager.findComponentAt(Native Method)
        at sun.awt.GlobalCursorManager._updateCursor(GlobalCursorManager.java:180)
        at sun.awt.GlobalCursorManager.updateCursorImmediately(GlobalCursorManager.java:82)
        at sun.awt.windows.WComponentPeer.updateCursorImmediately(WComponentPeer.java:538)
        at java.awt.Component.updateCursorImmediately(Component.java:2762)
        at java.awt.Container.remove(Container.java:1170)
        at java.awt.Container.remove(Container.java:1203)
        at javax.swing.plaf.basic.BasicTableHeaderUI.uninstallUI(BasicTableHeaderUI.java:333)
        at javax.swing.JComponent.setUI(JComponent.java:646)
        at javax.swing.table.JTableHeader.setUI(JTableHeader.java:437)
        at javax.swing.table.JTableHeader.updateUI(JTableHeader.java:451)
        at javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1206)
        at javax.swing.SwingUtilities.updateComponentTreeUI(SwingUtilities.java:1197)
        at javax.swing.table.JTableHeader.updateUI(JTableHeader.java:455)
        at javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1206)
        at javax.swing.SwingUtilities.updateComponentTreeUI(SwingUtilities.java:1197)
        at javax.swing.table.JTableHeader.updateUI(JTableHeader.java:455)
        at javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1206)
        at javax.swing.SwingUtilities.updateComponentTreeUI(SwingUtilities.java:1197)
etc.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class StackOverflowHeader extends JTableHeader implements TableCellRenderer {
    public StackOverflowHeader() {
        setDefaultRenderer(this);
    }

    public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int col) {
        return new JLabel(String.valueOf(value));
    }

    private static class SimpleTableDemo extends JPanel {
        public SimpleTableDemo() {
            super(new GridLayout(1,0));

            String[] columnNames = {"First Name",
                "Last Name",
                "Sport",
                "# of Years",
            "Vegetarian"};

            Object[][] data = {
                {"Mary", "Campione",
                "Snowboarding", new Integer(5), new Boolean(false)},
                {"Alison", "Huml",
                "Rowing", new Integer(3), new Boolean(true)},
                {"Kathy", "Walrath",
                "Knitting", new Integer(2), new Boolean(false)},
                {"Sharon", "Zakhour",
                "Speed reading", new Integer(20), new Boolean(true)},
                {"Philip", "Milne",
                "Pool", new Integer(10), new Boolean(false)}
            };

            final JTable table = new JTable(data, columnNames);
            table.setPreferredScrollableViewportSize(new Dimension(500, 70));
            //table.setFillsViewportHeight(true);
            table.setTableHeader(new StackOverflowHeader());

            //Create the scroll pane and add the table to it.
            JScrollPane scrollPane = new JScrollPane(table);

            //Add the scroll pane to this panel.
            add(scrollPane);
        }

    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        SimpleTableDemo newContentPane = new SimpleTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
        SwingUtilities.updateComponentTreeUI(frame); //calls StackOverflowHeader.updateUI()
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
        });
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
override updateUI() as follows
    public void updateUI(){
        setUI((TableHeaderUI)UIManager.getUI(this));
    }