I'm working in a project in which we have several domain classes to model business data. Those classes are simple POJO's and I have to display several tables using them. For example, consider this class:
public class Customer {
private Long id;
private Date entryDate;
private String name;
private String address;
private String phoneNumber;
public Customer(Long id, Date entryDate, String name, String address, String phoneNumber) {
this.id = id;
this.entryDate = entryDate;
this.nombre = name;
this.domicilio = address;
this.telefono = phoneNumber;
}
// Getters and setters here
}
I have created then my own table model extending from AbstractTableModel in order to work directly with Customer
class:
public class CustomerTableModel extends AbstractTableModel {
private final List<String> columnNames;
private final List<Customer> customers;
public CustomerTableModel() {
String[] header = new String[] {
"Entry date",
"Name",
"Address",
"Phone number"
};
this.columnNames = Arrays.asList(header);
this.customers = new ArrayList<>();
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return Date.class;
case 1: return String.class;
case 2: return String.class;
case 3: return String.class;
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Customer customer = getCustomer(rowIndex);
switch (columnIndex) {
case 0: return customer.getEntryDate();
case 1: return customer.getName();
case 2: return customer.getAddress();
case 3: return customer.getPhoneNumber();
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex < 0 || columnIndex >= getColumnCount()) {
throw new ArrayIndexOutOfBoundsException(columnIndex);
} else {
Customer customer = getCustomer(rowIndex);
switch (columnIndex) {
case 0: customer.setEntryDate((Date)aValue); break;
case 1: customer.setName((String)aValue); break;
case 2: customer.setAddress((String)aValue); break;
case 3: customer.setPhoneNumber((String)aValue); break;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
}
@Override
public int getRowCount() {
return this.customers.size();
}
@Override
public int getColumnCount() {
return this.columnNames.size();
}
@Override
public String getColumnName(int columnIndex) {
return this.columnNames.get(columnIndex);
}
public void setColumnNames(List<String> columnNames) {
if (columnNames != null) {
this.columnNames.clear();
this.columnNames.addAll(columnNames);
fireTableStructureChanged();
}
}
public List<String> getColumnNames() {
return Collections.unmodifiableList(this.columnNames);
}
public void addCustomer(Customer customer) {
int rowIndex = this.customers.size();
this.customers.add(customer);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void addCustomers(List<Customer> customerList) {
if (!customerList.isEmpty()) {
int firstRow = this.customers.size();
this.customers.addAll(customerList);
int lastRow = this.customers.size() - 1;
fireTableRowsInserted(firstRow, lastRow);
}
}
public void insertCustomer(Customer customer, int rowIndex) {
this.customers.add(rowIndex, customer);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void deleteCustomer(int rowIndex) {
if (this.customers.remove(this.customers.get(rowIndex))) {
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
public Customer getCustomer(int rowIndex) {
return this.customers.get(rowIndex);
}
public List<Customer> getCustomers() {
return Collections.unmodifiableList(this.customers);
}
public void clearTableModelData() {
if (!this.customers.isEmpty()) {
int lastRow = customers.size() - 1;
this.customers.clear();
fireTableRowsDeleted(0, lastRow);
}
}
}
Until now everything is just fine. However this approach has at least two problems:
Since I have to implement one table model per class, then I'll generate a lot of repetitive code to essentially do three things: define an appropriate table header, add/remove objects to/from an underlying structure (list), override both
setValueAt()
andgetValueAt()
methods to work with user-defined objects.Let's say I have the very same list of Customers but I have to present this in two different tables, with different header or data. I would have to subclass my table model and override whatever it needs to be overriden in order to fulfill this requirement. It doesn't feel elegant at all.
Question: Is there some way to get rid of boilerplate code making my table model flexible and reusable?