nattableglazedlists

NullpointerException when using GroupBy feature


I use NatTables group by feature. When activating groupby I sometimes get an exception during the paint event like this ....

java.lang.NullPointerException: Cannot read field "left" because "node" is null
    at ca.odell.glazedlists.impl.adt.barcode2.FourColorTree.get(FourColorTree.java:169)
    at ca.odell.glazedlists.TreeList.getTreeNode(TreeList.java:303)
    at ca.odell.glazedlists.TreeList.get(TreeList.java:288)
    at org.eclipse.nebula.widgets.nattable.data.ListDataProvider.getRowObject(ListDataProvider.java:64)
    at pml.rcp.ui.table.CellTableHintAdapter.accumulateConfigLabels(CellTableHintAdapter.java:39)

When I explicitly sort the first column before invoking group by (using D&D to the nattable header) I don't get the exception (with the very same data).

I get the same effect when invoking natTable.doCommand(new TreeCollapseAllCommand());

I read some reports about FourColorTree from glazedlists causing such problems, and that it could be a race condition, and the header of FourColorTree mentions it's a kind of prototype, however I'm on the latest glazedlist version (1.11.0).

I'm afraid the problem is not simple to reproduce, especially as the NatTable samples work perfectly fine. So I have 2 questions:

  1. Is this a somehow known problem, maybe with a known workaround I can try?
  2. Is there a way to change the underlying Algorithm? (Like not using glazedlist or at least not the FourColorTree class).

Solution

  • Dirk, thanks for your valuable input and thanks even more for this great component! I think I finally figured out what's going on.

    It seems to me glazedlists TreeList gets rebuilt in background when grouping changes (triggered by eg. GroupByColumnIndexCommand).

    While this rebuild is still running NatTable receives paint events.

    The paint events lead to the invocation of the label accumulators.

    My label accumulator needs to access the underlying object, as the labels (coloring etc.) depend on the objects state.

    In order to get the Object, I invoke IRowDataProvider.getRowObject.

    The concrete implementation is org.eclipse.nebula.widgets.nattable.data.ListDataProvider, which internally invokes TreeList (which is not finished as it is rebuilt in the background).

    I worked around the problem shielding all accesses to IRowDataProvider in a try/catch block when accessing them in the label accumulators. This seems to work as further paint events arrive once the tree is finally built, and then I can also provide the proper labels.

    I'm not sure if ListDataProvider.getRowObject should throw a NPE in this situation. Maybe the paint events shouldn't be processed if the underlying datastructure is still rebuilding, but of course that's just an idea.

    Possibly the problem doesn't happen in the samples, as I have like 3k Objects in the table, so rebuilding the tree takes a bit longer.

    Finally the full stacktrace, just in case you are interested.

    java.lang.NullPointerException: Cannot read field "left" because "node" is null 
    at ca.odell.glazedlists.impl.adt.barcode2.FourColorTree.get(FourColorTree.java:169) 
    at ca.odell.glazedlists.TreeList.getTreeNode(TreeList.java:303) 
    at ca.odell.glazedlists.TreeList.get(TreeList.java:288) 
    at org.eclipse.nebula.widgets.nattable.data.ListDataProvider.getRowObject(ListDataProvider.java:64) 
    at pml.rcp.ui.table.PMRowObjectAccessor.getRowObject(PMRowObjectAccessor.java:16) 
    at pml.rcp.ui.table.PMTableConfigInitializer$MetaLabelAccumulator.accumulateConfigLabels(PMTableConfigInitializer.java:388) 
    at org.eclipse.nebula.widgets.nattable.layer.cell.AggregateConfigLabelAccumulator.accumulateConfigLabels(AggregateConfigLabelAccumulator.java:48) 
    at org.eclipse.nebula.widgets.nattable.layer.AbstractLayer.getConfigLabelsByPosition(AbstractLayer.java:110) 
    at org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy.GroupByDataLayer.getConfigLabelsByPosition(GroupByDataLayer.java:758) 
    at org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy.GroupByDisplayConverter.getDisplayValue(GroupByDisplayConverter.java:168) 
    at pml.rcp.ui.table.PMGroupByDisplayConverter.getDisplayValue(PMGroupByDisplayConverter.java:26) 
    at org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy.GroupByDisplayConverter.canonicalToDisplayValue(GroupByDisplayConverter.java:90) 
    at org.eclipse.nebula.widgets.nattable.layer.cell.CellDisplayConversionUtils.convertDataType(CellDisplayConversionUtils.java:35) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.AbstractTextPainter.convertDataType(AbstractTextPainter.java:213) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter.paintCell(TextPainter.java:180) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper.paintCell(CellPainterWrapper.java:70) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.BackgroundPainter.paintCell(BackgroundPainter.java:55) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.decorator.CellPainterDecorator.paintCell(CellPainterDecorator.java:303) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper.paintCell(CellPainterWrapper.java:70) 
    at org.eclipse.nebula.widgets.nattable.tree.painter.IndentedTreeImagePainter.paintCell(IndentedTreeImagePainter.java:319) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper.paintCell(CellPainterWrapper.java:70) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.decorator.PaddingDecorator.paintCell(PaddingDecorator.java:203) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper.paintCell(CellPainterWrapper.java:70) 
    at org.eclipse.nebula.widgets.nattable.painter.cell.BackgroundPainter.paintCell(BackgroundPainter.java:55) 
    at org.eclipse.nebula.widgets.nattable.painter.layer.CellLayerPainter.paintCell(CellLayerPainter.java:222) 
    at org.eclipse.nebula.widgets.nattable.painter.layer.CellLayerPainter.paintLayer(CellLayerPainter.java:88) 
    at org.eclipse.nebula.widgets.nattable.painter.layer.GridLineCellLayerPainter.paintLayer(GridLineCellLayerPainter.java:143) 
    at org.eclipse.nebula.widgets.nattable.selection.SelectionLayerPainter.paintLayer(SelectionLayerPainter.java:114) 
    at org.eclipse.nebula.widgets.nattable.layer.CompositeLayer$CompositeLayerPainter.paintLayer(CompositeLayer.java:1069) 
    at org.eclipse.nebula.widgets.nattable.layer.CompositeLayer$CompositeLayerPainter.paintLayer(CompositeLayer.java:1069) 
    at org.eclipse.nebula.widgets.nattable.painter.layer.NatLayerPainter.paintLayer(NatLayerPainter.java:61) 
    at org.eclipse.nebula.widgets.nattable.NatTable.paintNatTable(NatTable.java:521) 
    at org.eclipse.nebula.widgets.nattable.NatTable.paintControl(NatTable.java:516) 
    at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:234) 
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89) 
    at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4273) 
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1066) 
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1090) 
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1075) 
    at org.eclipse.swt.widgets.Composite.WM_PAINT(Composite.java:1536)