The other day, a colleague showed me a window that was not working well. Scrolling a JTable was throwing lots of Exceptions and breaking the rendering. The strange thing was that this window worked perfectly on my machine. Here is the stack trace from the logs:
java.lang.NullPointerException at javax.swing.JTable.prepareRenderer(Unknown Source) at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source) at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source) at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source) at javax.swing.plaf.ComponentUI.update(Unknown Source) at javax.swing.JComponent.paintComponent(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JViewport.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintToOffscreen(Unknown Source) at javax.swing.BufferStrategyPaintManager.paint(Unknown Source) at javax.swing.RepaintManager.paint(Unknown Source) at javax.swing.JComponent._paintImmediately(Unknown Source) at javax.swing.JComponent.paintImmediately(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.access$700(Unknown Source) at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$400(Unknown Source) at java.awt.EventQueue$2.run(Unknown Source) at java.awt.EventQueue$2.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)
It is not easy to debug a problem when the whole stack is Swing code, but we managed to find the exact column in the JTable that triggered the problem (x value in renderer is 5). Looking at the model, we saw the following code:
@Override public Class> getColumnClass(int column) { switch (column) { case 0: return String.class; // Name case 1: return Date.class; // Time case 2: return Double.class; // Bid case 3: return Double.class; // Ask case 4: return String.class; // Type case 5: return boolean.class; // Staled case 6: return Date.class; // ExpiryDate case 7: return String.class; // Maturity case 8: return String.class; // InstrumentType }
Do you see it? The boolean in lower case? I never thought about it, but this seems to give troubles to the Swing renderer. It expects of course "Boolean" with an upper case. The reason I was not experiencing the problem? I am running Java 7, while my colleague was running with Java 6. This means that we are not the first developpers to get bitten by this case ;).