15

Can someone explain to me why I am getting a NullPointerException in the getRowCount() method? The variable is initialized with an empty ArrayList...

public class BeschriftungssetTableModel extends DefaultTableModel {

    private static final long serialVersionUID = -4980235976337188354L;

    private List<BeschriftungssetBean> data = new ArrayList<>();


    public void setData(List<BeschriftungssetBean> data) {
        this.data = data;
    }

    @Override
    public int getColumnCount() {
        return 1;
    }

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public Object getValueAt(int row, int column) {
        return data.get(row).getBezeichnung();
    }

    @Override
    public String getColumnName(int column) {
        return "Bezeichnung";
    }

    public static void main(String[] args) {
        BeschriftungssetTableModel beschriftungssetTableModel = new BeschriftungssetTableModel();
        beschriftungssetTableModel.getRowCount();
    }
}



public class BeschriftungssetBean {
    private String objId;
    private String bezeichnung;

    public String getBezeichnung() {
        return bezeichnung;
    }

    public void setBezeichnung(String bezeichnung) {
        this.bezeichnung = bezeichnung;
    }

    public String getObjId() {
        return objId;
    }

    public void setObjId(String objId) {
        this.objId = objId;
    }
}

Exception in thread "main" java.lang.NullPointerException
at ch.aaa.xxx.yyy.gruppen.plugin.anzeige.beschriftungseinstellungen.BeschriftungssetTableModel.getRowCount(BeschriftungssetTableModel.java:36)
at javax.swing.table.DefaultTableModel.setDataVector(DefaultTableModel.java:224)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:124)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:106)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:86)
at ch.aaa.xxx.yyy.gruppen.plugin.anzeige.beschriftungseinstellungen.BeschriftungssetTableModel.<init>(BeschriftungssetTableModel.java:18)
at ch.aaa.xxx.yyy.gruppen.plugin.anzeige.beschriftungseinstellungen.BeschriftungssetTableModel.main(BeschriftungssetTableModel.java:50)
ave4496
  • 2,950
  • 3
  • 21
  • 48
  • 3
    Could you add the stack trace for the `NullPointerException`? – deHaar Aug 17 '18 at 07:14
  • I already debugged the method and it says that "data" in "getRowCount" is null which then causes the exception. – ave4496 Aug 17 '18 at 07:18
  • OK, I see that is weird... You haven't initialized it with `null` (but with raw type `ArrayList<>`)... – deHaar Aug 17 '18 at 07:21
  • In the main method you can see that nothing else is done – ave4496 Aug 17 '18 at 07:23
  • 5
    If your plan is to replace everything DefaultTableModel does by your own methods, and to use your own list rather than the data that DefaultTableModel uses, implement AbstractTableModel instead of extending DefaultTableModel. – JB Nizet Aug 17 '18 at 07:29
  • 3
    Unrelated: consider not mixing languages in your code. And as BeschriftungsMengeBohne sounds really bad, I would rather go all English `InscriptionSetBean` for example. – GhostCat Aug 17 '18 at 07:41
  • 1
    I would definately go with @JBNizet 's advice and extend AbstractTableModel – keuleJ Aug 17 '18 at 08:06
  • @GhostCat this clearly depends on the context. Although I've preached the same advice in the past, some domains are better expressed in the native language of the participants, even if it leads to an ugly english-foreign mix. – spi Aug 17 '18 at 11:13
  • After a long time, I'm seeing the first question complaining `NullPointerException`, which was not closed. ;) – Hardik Modha Aug 17 '18 at 11:54
  • @spi: And it makes your code MUCH harder to read when you're open-sourcing parts of it, accepting a foreigner into your team, or asking questions about it on stackoverflow. Production code should be English-only, period. – Guntram Blohm Aug 17 '18 at 15:45
  • @HardikModha When the answer can be somewhat useful to somebody else (because it depends on some technology/library/etc) and not just the OP. – user202729 Aug 17 '18 at 15:46
  • @user202729 That was a sarcastic comment. It was indeed a good question and I also learned something new today! :) – Hardik Modha Aug 17 '18 at 16:49
  • 1
    @GuntramBlohm well it's complicated enough to know all the special terms that exist in german... let alone finding the correct translation... there would be absolutely no benefits for our projects since speaking german is a requirement – ave4496 Aug 18 '18 at 15:21
  • @GuntramBlohm there is hardly anything true all the time. When there is no chance the code will be outsourced someday (eg. legal reasons) and your business is very specifiy to a region/country/language, you will only get brain overload and misunderstanding not using your native language. But I agree, the general rule of thumb should be all-english. – spi Aug 18 '18 at 20:55

2 Answers2

28

The constructor of DefaultTableModel calls getRowCount before the subclass had a chance to initialize its content, thus leading to NPE with your implem. This is a bad design of the base class, as calling overridable methods from within a constructor is considered a bad practice, but hey, Swing API has quite a few of these :)

Cf. What's wrong with overridable method calls in constructors?

spi
  • 1,673
  • 13
  • 19
  • 1
    *"...as calling overridable methods from within a constructor is considered a bad practice..."* For precisely this reason. :-) – T.J. Crowder Aug 17 '18 at 16:48
13

Do not extend DefaultTableModel, extend AbstractTableModel instead.

DefaultTableModel uses a Vector to maintain the data and does not expect you having your own data in a subclass. As @spi wrote, it is calling getRowCount which was overriden to return the size of data that is not yet initialized.

The AbstractTableModel is easy to extend (DefaultTableModel also does), just these 3 methods need to be implemented (already done in questions code):

public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);

Others methods can be overridden to adjust its behavior like isCellEditable or getColumnClass. If the data is changed the appropriate fireXXX method should be called so the registered listeners are invoked (e.g. JTable using that model).

An alternative is to implement TableModel, but AbstractTableModel takes care of some standard (nasty?) functionality like maintaining the listeners.

(bad alternative, just check for null, but this probably will mess up with the DefaultTableModel code - do not do this)

user85421
  • 28,957
  • 10
  • 64
  • 87