A NullPointerException is thrown when trying to serialize a TableModel object while the associated JTable object is visible in a JFrame. I created a minimal, reproducible Example and will also include the Stack-Trace.
The Nullpointer is described like this:
Cannot invoke "javax.swing.JTable.getColumnModel()"
because "this.table" is null
But why is this method called anyway? I am serializing the Model, not the JTable.
When not using a JFrame, it works fine.
I hope someone can help. I am using AdoptOpenJDK14 (14.0.2.12-hotspot)
Here is the minimal, reproducible Example:
Serialization.java (Entrypoint of the Program)
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.WindowConstants;
public class Serialization {
public static void main(String[] args) throws Exception {
MyAbstractModel model = new MyAbstractModel();
JTable table = new JTable(model);
// After creating the frame, putting in the table and setting it to visible the exception will be thrown when trying to serialize below
JFrame frame = new JFrame();
frame.add(table);
frame.setSize(300,300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("some.dat"));
oos.writeObject(model);
oos.close();
}
}
MyAbstractModel.java (The Model to Serialize)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.table.AbstractTableModel;
public class MyAbstractModel extends AbstractTableModel {
private List<String> list = new ArrayList<>();
public MyAbstractModel(){
list = Collections.synchronizedList(new ArrayList<>());
list.add("Test1");
list.add("Test2");
list.add("Test3");
list.add("Test4");
}
@Override
public int getRowCount() {
return 10;
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return rowIndex + "-" + columnIndex;
}
@Override
public String getColumnName(int column) {
return "Column " + column;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
// TODO
}
}
Some.java (Just a Serializable Test Object)
import java.io.Serializable;
public class Some implements Serializable {
private static final long serialVersionUID = 1L;
public final int num;
public final String name;
transient int ignoreNum;
public Some(int num, String name, int ignoreNum) {
this.num = num;
this.name = name;
this.ignoreNum = ignoreNum;
}
@Override
public String toString() {
return "Some{" +
"num=" + num +
", name='" + name + '\'' +
", ignoreNum=" + ignoreNum +
'}';
}
}
This is the Stacktrace I got.
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "javax.swing.JTable.getColumnModel()" because "this.table" is null at java.desktop/javax.swing.plaf.basic.BasicTableUI.getPreferredSize(BasicTableUI.java:1768) at java.desktop/javax.swing.JComponent.getPreferredSize(JComponent.java:1680) at java.desktop/javax.swing.JTable.setWidthsFromPreferredWidths(JTable.java:3205) at java.desktop/javax.swing.JTable.doLayout(JTable.java:3117) at java.desktop/java.awt.Container.validateTree(Container.java:1722) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validate(Container.java:1657) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2762) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4844) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "javax.swing.JTable.getColumnModel()" because "this.table" is null
at java.desktop/javax.swing.plaf.basic.BasicTableUI.getPreferredSize(BasicTableUI.java:1768) at java.desktop/javax.swing.JComponent.getPreferredSize(JComponent.java:1680) at java.desktop/javax.swing.JTable.setWidthsFromPreferredWidths(JTable.java:3205) at java.desktop/javax.swing.JTable.doLayout(JTable.java:3117) at java.desktop/java.awt.Container.validateTree(Container.java:1722) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validateTree(Container.java:1731) at java.desktop/java.awt.Container.validate(Container.java:1657) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2762) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4844) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)