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()and- getValueAt()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?
 
    