Continuo il diario della mia esperienza Java e Groovy parlando di una libreria per la persistenza dei dati e di una scappatoia per realizzare derivati di AbstractTableModel in modo rapido: ovviamente sfruttando la capacità di Groovy di essere compilato in byte code e quindi di integrarsi con il resto dell’applicazione sviluppato in Java.
Per la persistenza dei dati sto utilizzando la libreria JPersist (di cui ignoro ancora le performance) che consente di accedere ai dati secondo il paradigma Object Oriented. A differenza dei framework di persistenza classici (compresi quelli integrati di Java) JPersist non ha bisogno di troppi file xml (a parte uno in cui scriviamo i parametri di connessione al DB.
Per accedere ai dati abbiamo bisogno di una classe che abbia lo stesso nome della tabella (o quasi uguale) e (per la scrittura dei dati) sia derivata da jpersist.PersistentObject; impostiamo come attributi della classe, i campi della tabella relativa e, fatto questo, avremmo bisogno di sbobinarci la solita pippa sulle proprietà di una classe Java ossia scrivere i metodi getter e setter dei relativi attributi. Oggigiorno questo non è più un problema ma (chissà se mai lo capiranno alla Sun) si perde in leggibilità. Molto meglio rivolgersi a Groovy per la realizzazione di una classe persistente; al solito, non meravigliatevi della brevità del codice:
import jpersist.*
public class Customer extends PersistentObject{
Integer id
String firstName
String lastName
}
Niente virgole, niente getter e setter…nient’altro. Mi aspetto che nel DB esista una tabella Customer o customer o customers o qualsiasi nome *customer* con i campi id, firstname e lastname.
Vi rimando alla documentazione di JPersist per ulteriori dettagli su come fare le query, gli update, etc.
Vi parlo invece di come visualizzare i dati: per farlo abbiamo bisogno di una JTable o, meglio, di una JXTable, e di un TableModel. Per fare un TableModel ci vuole il legn…ehm…i dati e un modo per accedervi. Dobbiamo definire le colonne ecc, ecc.
Preleviamo i dati. Io ho realizzato un metodo per prelevare un’arraylist di clienti:
public ArrayList getCustomers() {
try {
DatabaseManager dbm = DatabaseManager.getXmlDefinedDatabaseManager("mio_db_definito_nel_file_xml");
ArrayList result = (ArrayList) dbm.loadObjects(new ArrayList(), Customer.class);
dbm.close();
return result;
} catch (Exception ex) { }
return null;
}
Ora mi serve il TableModel che costruirò sulla base di questo ArrayList; siccome a me piace molto il codice generico e poco lungo, l’ho scritto in Groovy usando la reflection:
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
import groovy.swing.SwingBuilder
import java.lang.reflect.Field;
class GModel{
private static Class getFieldType(Object o, fieldName){
Field f = o.getClass().getDeclaredField(fieldName);
return f.getType();
}
public static AbstractTableModel getModel(ArrayList dataList,
String[] fieldNames,
String[] fieldLabels){
def swing = new SwingBuilder()
def i=0;
def gModel
if (dataList.size()>0){
Object o = dataList[0];
gModel = swing.tableModel(list:dataList) {
fieldNames.each{
propertyColumn(header:fieldLabels[i], propertyName:it, type:getFieldType(o,it))
i++
}
}
}
else
{
gModel = swing.tableModel(list:dataList) {
fieldNames.each{
propertyColumn(header:fieldLabels[i], propertyName:it)
i++
}
}
}
return gModel
}
}
Il metodo statico getModel consente di fornire una lista di oggetti, un elenco di campi da visualizzare e le label delle relative colonne (ok avrei potuto utilizzare anche una Map). Tale metodo usa il SwingBuilder di Groovy per creare il table model in modo davvere eccezionale: provate a confrontare la routine con i table model scritti in java; ve lo ripropongo per maggiore dettaglio:
def swing = new SwingBuilder()
def i=0;
def gModel = swing.tableModel(list:dataList) {
fieldNames.each{
propertyColumn(header:fieldLabels[i], propertyName:it, type:getFieldType(o,it))
i++
}
}
Quindi i dati li passo con l’attributo list di swing.tableModel ed al table model aggiungo (per ogni campo scelto) una propertycolumn che presenta una label, il nome dell’attributo (della classe Customer) ed il tipo del campo. A sua volta il tipo del campo lo recuperiamo genericamente usando la reflection.
private static Class getFieldType(Object o, fieldName){
Field f = o.getClass().getDeclaredField(fieldName);
return f.getType();
}
Penso che non serva passare un’istanza dell’oggetto ma sinceramente non ho avuto molto tempo per le ottimizzazione (volevo usare i generics ma non ci sono riuscito). Ad ogni modo il metodo recupera la classe ed il campo relativo al nome dell’attributo e ne restituisce il type.
Il table model così creato presenterà, una volta compilato, tutti i metodi, getter e setter di un table model classico. Stessa qualità, stesse performance meno codice!
Se avete suggerimenti e migliorie commentate pure
Zac
P.S.: In entrambi i metodi della classe lo statement “return” è superfluo dato che ogni metodo Groovy capisce dinamicamente quale delle sue variabili deve restituire.