1

I ran into trouble saving a JTable (containing the model). Simply serializing the model is no problem as far as I only add rows and Data. The moment where I remove one row and try to save generates an IO exception. My code:

This code is used to save the model:

public static void saveModel() {
        if (isDatabasePathSet == true) {
            FileOutputStream fos = null;
            ObjectOutputStream out = null;

            try {
                table.clearSelection();
                table.repaint();
                if (table.isEditing()) { // prevent saving when user is editing a cell
                    table.getCellEditor().stopCellEditing();
                }

                fos = new FileOutputStream("test" + ".dbd");
                out = new ObjectOutputStream(fos);
                out.writeObject(model); // here I save the table contents
                out.writeObject(lfdNr); // this is just an increasing number / primary key
            } catch (Exception errWrite) {
                System.out.println("Fehler beim speichern der Datenbank");
            } finally {
                try {
                    fos.close();
                    out.close();
                } catch (Exception errClose) {
                    System.out.println("Fehler beim Schließen der Dateiströme");
                }
            }
        } else {
            JOptionPane
                    .showMessageDialog(
                            mainGui,
                            "<html>Es ist keine Datenbank ausgewählt, <br>bitte wählen Sie zunächst eine Datenbank im Menü aus: <br><br><i>Datenbank --> Datenbankpfad festlegen...</i></html>",
                            "Datenbankpfad fehlt", JOptionPane.WARNING_MESSAGE);
        }
    }

The "model" is defined like this:

model = new DefaultTableModel(new Object[][] {  },
    new String[] { "Lfd. Nr.", "FB Nr.", "Melde Nr.", "Betra Nr.", "Datum",
        "Ort", "Str. Km.", "Sprz.", "Mitarbeiter",
        "Auftrag / Objekt(e)", "Abgeschlossen" }) {

            private static final long serialVersionUID = 1L;
    Class[] columnTypes = new Class[] { Integer.class, String.class, Integer.class,
            Integer.class, String.class, String.class, String.class,
            String.class, String.class, String.class, Boolean.class };

    public Class getColumnClass(int columnIndex) {
        return columnTypes[columnIndex];
    }
};

I delete a row like this:

JButton buttonDeleteTask = new JButton("Auftrag entfernen");
buttonDeleteTask.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        int selectedRows[] = table.getSelectedRows();
        for (int i = 0; i < selectedRows.length; i++) {
            model.removeRow(selectedRows[i] - i);
        }
    }
});

This is the exception I get:

Fehler beim speichern der Datenbank
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1761)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:779)
    at javax.swing.JComponent.paint(JComponent.java:1055)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JViewport.paint(JViewport.java:731)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JSplitPane.paintChildren(JSplitPane.java:1047)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
    at javax.swing.JComponent.paintChildren(JComponent.java:888)
    at javax.swing.JComponent.paint(JComponent.java:1064)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5232)
    at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:295)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1249)
    at javax.swing.JComponent._paintImmediately(JComponent.java:5180)
    at javax.swing.JComponent.paintImmediately(JComponent.java:4991)
    at javax.swing.RepaintManager$3.run(RepaintManager.java:808)
    at javax.swing.RepaintManager$3.run(RepaintManager.java:796)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:769)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:718)
    at javax.swing.RepaintManager.access$1100(RepaintManager.java:62)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1677)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:738)
    at java.awt.EventQueue.access$300(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:699)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:708)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

I don't see where I get a Null Pointer in the AWT-EventQue, do I have to update the model before serializing it?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Flatron
  • 1,375
  • 2
  • 12
  • 33
  • 1
    Looking at the source code this is caused because `table.getBounds()` returns null which shouldn't. Check that value to see when that happens. Is `saveModel` called in the EDT? – DSquare Mar 03 '15 at 09:36
  • 1
    For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). – Andrew Thompson Mar 03 '15 at 09:44
  • @DSquare Where do I find the "table.getBounds()" call? I can't locate it in my code, what calls this method? – Flatron Mar 03 '15 at 09:54
  • @Flatron As indicated in the stack trace, in the line 1761 [here](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/javax/swing/plaf/basic/BasicTableUI.java#BasicTableUI.paint%28java.awt.Graphics%2Cjavax.swing.JComponent%29). – DSquare Mar 03 '15 at 09:55
  • Okay good, but how can I fix this then, I could set the bounds manually. But how is this connected to the fact that the error only occurs if I remove a row? Maybe removing a row resets the bounds to the null pointer. – Flatron Mar 03 '15 at 10:01
  • That is just a manifestation of something wrong you are doing in your code, you don't have to set the bounds yourself to "fix it". Can't help much more without an MCVE. It is worrysome that saveModel does things that **have to** be in the EDT (updating JTable) and things that *shouldn't* (but can) be there (file I/O), but I doubt that's the cause of this problem. – DSquare Mar 03 '15 at 10:08
  • Okay I will try to build the most simple example of this in a new project. – Flatron Mar 03 '15 at 10:20

1 Answers1

1

Okay I found my problem. You need to detach the model from the table before serializing, else it will fail. So Serializing looks like this now:

[...]
    fos = new FileOutputStream("03032015.dbd");
                out = new ObjectOutputStream(fos);

                table.setModel(new DefaultTableModel()); // detach model from table while serializing to prevent it from failing
                out.writeObject(model);
                table.setModel(model);
[...]

After saving you can reapply your old model again without any problem.

Thanks to DSquare and Andrew Thompson I tried the MCVE (Minimal Complete Verifiable Example) or SSCCE (Short, Self Contained, Correct Example) approach which lead me to this post: Loading Java JTable: Why does it not work?

Community
  • 1
  • 1
Flatron
  • 1,375
  • 2
  • 12
  • 33
  • Interesting! That's usually what happens when you tackle your problem in a very clean way (doing an MCVE/SCCE). You can accept your own answer! – DSquare Mar 03 '15 at 12:59