Primi Passi con BeanIO (parte 1)

Nell’articolo Esportazione dati tramite annotation in Java abbiamo introdotto un framework per l’esportazione di dati in formato Excel e TXT mediante semplici annotation. Se siamo però interessati ad un framework più maturo la scelta non può cadere che su BeanIO, una libreria per il marshalling e l’unmarshalling di bean da uno stream, che supporta i formati di XML, CSV, delimitati e a lunghezza fissa e che si integra perfettamente nell’architettura di Spring Batch.

Esempio Base

Per comprendere i diversi aspetti del framework iniziamo con la realizzazione di un semplice esempio che poi estenderemo di volta in volta introducendo i diversi aspetti della libreria.  Per prima cosa creiamo quindi un progetto Maven ed inseriamo la dipendenza al framework:

Quindi introduciamo nel progetto le classi Customer e Address che saranno i bean che vogliamo serializzare e deserializzare.

Configurazione

Il comportamento di BeanIO può essere configurato mediante file XML, annotazioni o anche builder API. Per gli scopi di questo tutorial è preferibile utilizzare l’XML perchè a mio avviso è un metodo più completo e flessibile. Creiamo quindi nella cartella resources del progetto il file customer-mapping.xml che conterrà il seguente XML.

Di seguito è descritto il significato delle diverse sezioni del file:

<stream>

Questa sezione descrive il componente base utilizzati da BeanIO per mappare un flusso di input o una String in un oggetto Java. Possono essere presenti più tag <stream> nel file, per questo motivo è presente l’attributo name che consente di distinguerli.

Il formato dello stream è invece definito dall’attributo format che può assumere i valori: csv, delimited, xml, fixedlength e json. In funzione del tipo di stream BeanIO utilizza un diverso parser che può essere ulteriormente configurato attraverso il tag <parser>. Ad esempio nel caso di uno stream delimited è possibile sovrascrivere il delimitatore di default, che è la virgola, nel seguente modo:

<record> Ogni record letto o scritto sullo stream deve essere mappato attraverso il tag <record>. Nel file deve esserne presente almeno uno ed è utilizzato dal framework per validate il record ma soprattutto per eseguire il binding tra i valori del record e le proprietà del bean cui è mappato attraverso il tag <field>. Nell’esempio la classe del bean mappato è specificata nella proprietà class, ed assume il valore it.javaboss.bean.Customer, mentre le proprietà primitive sono da utilizzare sono indicate nella proprietà name del tag <field> . Nel caso del tipo Date è anche possibile specificare il formato della data.
<segment> Questa sezione serve a mappare un gruppo di campi in uno specifico record ed è utile, ad esempio, per indicare che i campi appartengono ad un oggetto annidato, come è il caso dell’oggetto Address dell’esempio. Naturalmente la proprietà class indica il tipo del bean annidato.

Il file di configurazione è letto mediante la classe StreamFactory, la quale è poi utilizzata, come vedremo in seguito, per generare istanze di oggetti BeanReader, BeanWriter, Marshaller e Unmarshaller.

Marshalling e Unmarshalling

Veniamo alla operazione più semplice che è possibile eseguire col framework che è quella di serializzare e deserializzare un singolo record. A partire dalla classe factory generata sopra invochiamo il metodo createMarshaller() per generare un’istanza dell’interfaccia Marshaller indicando il nome stream definito nel file XML. Su tale oggetto è poi possibile invocare il metodo marshal() sul bean per ottenere lo stream di output.

Si noti che la classe di utilità CustomerUtils definisce diverse costanti accessibili in modo statico conteneti istanze dei bean Customer e Address utilizzati. L’output prodotto, nel caso di stream csv, sarà:

Jennifer,Jones,05/02/2019,44 West 29th Street,New York,NY,10001

E’ possibile poi procedere con l’unmarshal dello stesso stream generato questa volta creando un oggetto Unmarshaller dalla classe factory, con le medesime modalità viste sopra, ed invocando su di esso il metodo unmarshal() sul record generato.

BeanWriter e BeanReader

In modo assolutamente analogo possiamo generare le classi per la scrittura dello stream su file, nel formato specificato, utilizzando istanze degli oggetti BeanReader, BeanWriter. Il codice per scrivere un csv su file è il seguente:

Il codice genererà come output un file customers.csv contenente i dati:

Jennifer,Jones,05/02/2019,44 West 29th Street,New York,NY,10001
Paul,Adams,05/02/2019,29 West 44th Street,New York,NY,10001

Analogamente il codice sorgente per leggere un file csv e deserializzarlo è il seguente:

Codice Sorgente

Il codice sorgente con l’esempio presentato è scaricabile qui bean-io.