views:

192

answers:

5

I have implemented a custom Table Model as follows:

public class MyTableModel extends AbstractTableModel {
    ...
    ...
    @Override
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }
    ...
    ...
}

I am getting NullPointerException thrown by the above method, when I display a JTable having the above TableModel.

I think that the exception is due to some empty cells in the database table.

If the exception is due to empty cells in the database table, then how to get around with this problem?

It is not mandatory for every column in the database to have some value. Some columns can contain nothing.

A: 

Perhaps:

public Class getColumnClass(int c) {
        return (getValueAt(0, c) == null ? Object.class : getValue(0, c).getClass());
  }

I hope it helps you.

Aito
+1  A: 

One issue is why you are getting a null for these specific coordinates. If it is legitimate and you just want nothing special to be rendered, then what you need to do is null-check and return Object.class e.g.,:

   public Class getColumnClass(int c) {
        Object o = getValueAt(0, c);
        if(o==null) return Object.class;
        return o.getClass()
    }

This will ensure that the default renderer is used, and since there is no value, nothing will be rendered.

Uri
+1  A: 

If cells can contain empty values, then calling getClass() on a null value will certainly give you the NPE. Sure you can check for null, but your real problem is more subtle than that.

The TableModel interface specifies that getColumnClass(int) should return "the most specific superclass for all the cell values in the column." From the looks of things, you could be returning any number of class types for a single column, effectively breaking the TableModel contract.

Typically, column types are static for a given set of table data, meaning the class for a column shouldn't change unless the underlying table data has changed. I think it's important to ask why you need to return such a specific value.

In the case where you want to render something specific for a given class type, you're better off rolling your own TableCellRenderer, and determining the Object type on a per-cell basis. From there you can do any specific rendering as needed.

Jason Nichols
A: 

The purpose of getColumnClass() is for choosing the TableCellRenderer. JTable has setDefaultRenderer(Class columnClass, TableCellRenderer renderer) for choosing which renderer to use. If you don't know what the datatypes are that you are going to be showing You can answer String.class for all columns and then for getValueAt(int,int) you can return String.valueOf() for the data.

Clint
A: 

In addition to the answers so far: Assuming your model is backed by a List (as suggested in your previous question) you'll see an IndexOutOfBoundsException if attempting to render your JTable when the TableModel contains no rows (i.e. the List is empty). This is a nasty edge case (as I realise you're attempting to render a ResultSet - How do you know the ResultSet won't be empty?).

To avoid this, why didn't you do what I suggested originally and determine each column's class from the ResultSetMetaData?

Adamski
Again this issue is handled in both of my suggestions which provide complete working code. Sometimes I wonder why I bother posting working code.
camickr
@camickr: I checked the example you posted and you're not using the ResultSetMetaData to determine column class either; you determine it dynamically by iterating over the data ... unless I'm missing something?
Adamski
I gave two solutions. A simple solution which uses the existing DefaultTableModel and does not require a custom model. The code handles null cells and and empty an model. This approach saves creating a custom model. The second solution is more involved as it requires using a "generic" custom model that can be used in many different situations. In this case I then included a static method to populate the model from a ResultSet. In this case the meta data is used to determine the column class. Both solutions provide the ability for dynamic addition/deletions/changes to the model.
camickr
In your first example I noticed you've subclasses JTable and overridden getColumnClass(int), and are then iterating using JTable's getValueAt(int, int). This is a little dangerous as you're working in terms of the view, not the model. If, for example you sort the JTable differently then getColumnClass(int) could return a different result for the same column.
Adamski