JiBX: XML binding per Java
Questa libreria opensource ci permette di creare un binding estremamente flessibile tra file XML e classi Java
Il progetto JiBX
JiBX è una libreria che permette di effettuare un mapping tra classe Java e file XML, in maniera molto più flessibile rispetto a progetti simili come JAXB e XMLBeans. La peculiarità infatti di questo progetto è proprio questa, ovvero permettere allo sviluppatore di svincolare abbastanza il suo codice dal file XML che verrà mappato, senza essere costretto ad utilizzare una struttura che può cambiare spesso, che male si adatta alla nostra classe e chi più ne ha più ne metta.
Vedremo qui un paio di esempi che cercano di mostrare le potenzialità di questo framework, per maggiori approfondimenti vi rimando all’homepage del progetto: http://jibx.sourceforge.net/
Un primo mapping
Immaginiamo di trovarci in una situazione in cui ci viene restituito un file XML da un servizio, magari a fronte di una chiamata che noi abbiamo effettuato. L’XML potrebbe ad esempio essere come il seguente
<?xml version="1.0" encoding="ISO-8859-1"?> <SERVICE_RESPONSE> <NAME>Federico</NAME> <SURNAME>Paparoni</SURNAME> <EMAIL>mail at javastaff dot com</EMAIL> <ID>ABCDEFGHILMNO</ID> <STREET>VIA ROMA</STREET> <NUMBER>23</NUMBER> <CITY>CASAL DEI PAZZI</CITY> <CAP>12345</CAP> </SERVICE_RESPONSE>
Dal punto di vista della nostra applicazione però noi non abbiamo una classe che mappa tutte le informazioni contenute in questo file, perchè la logica del nostro programma ci ha portato a suddividere le informazioni in due differenti classi, Persona e Indirizzo
package com.javastaff.testjibx; public class Indirizzo { private String via; private int numeroCivico; private String citta; private String cap; public String getVia() { return via; } public void setVia(String via) { this.via = via; } public int getNumeroCivico() { return numeroCivico; } public void setNumeroCivico(int numeroCivico) { this.numeroCivico = numeroCivico; } public String getCitta() { return citta; } public void setCitta(String citta) { this.citta = citta; } public String getCap() { return cap; } public void setCap(String cap) { this.cap = cap; } }
package com.javastaff.testjibx; public class Persona { private String codiceFiscale; private String nome; private String cognome; private String email; private Indirizzo indirizzo; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getCognome() { return cognome; } public void setCognome(String cognome) { this.cognome = cognome; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Indirizzo getIndirizzo() { return indirizzo; } public void setIndirizzo(Indirizzo indirizzo) { this.indirizzo = indirizzo; } public String getCodiceFiscale() { return codiceFiscale; } public void setCodiceFiscale(String codiceFiscale) { this.codiceFiscale = codiceFiscale; } }
Come fare? Proprio in situazioni del genere (e in molte altre più complicate) ci viene in aiuto JiBX, che attraverso un file di mapping ci permette di associare i vari tag presenti nel file XML ad una o più classi di risposta. In questo caso il file di mapping è abbastanza semplice, come quello che potete vedere qui di seguito
<?xml version="1.0" encoding="ISO-8859-1"?> <binding> <mapping name="SERVICE_RESPONSE"class
=
"com.javastaff.testjibx.Persona"
> <value name="NAME" field="nome"/> <value name="SURNAME" field="cognome"/> <value name="EMAIL" field="email"/> <value name="ID" field="codiceFiscale"/> <structure field="indirizzo"> <value name="STREET" field="via"/> <value name="NUMBER" field="numeroCivico"/> <value name="CITY" field="citta"/> <value name="CAP" field="cap"/> </structure> </mapping> </binding>
Attraverso il tag “mapping” diciamo a JiBX di utilizzare una certa classe per mappare un determinato tag. All’interno di quest’ultimo possiamo prendere sia altri tag ed associarli a variabili della nostra classe, sia recuperare il contenuto del tag ed utilizzarlo nello stesso modo oppure ricercare il valore di un certo attributo presente nel tag. Nel file di mapping che vedete riportato noi abbiamo associato i valori contenuti nei tag NAME, SURNAME, EMAIL e ID a quattro diverse variabili presenti nella classe Persona.
Successivamente abbiamo incontrato la parte che più differenzia l’XML dal dominio della nostra applicazione. Infatti abbiamo preso in considerazione la variabile (field) indirizzo di Persona, che è un’istanza di Indirizzo, utilizzando il tag “structure”. Con questo abbiamo comunicato a JiBX che il mapping che veniva effettuato all’interno di questo tag, doveva riferirsi alla variabile indirizzo e non all’istanza di Persona. In questo modo abbiamo settato i vari campi di Indirizzo che erano presenti nel file di mapping con lo stesso procedimento visto fin’ora.
Prima di poter provare questo esempio dobbiamo avviare la compilazione di alcuni stub che servono a JiBX a runtime per effettuare il mapping. Da riga di comando dobbiamo avviare il seguente programma
java -jar $JIBXHOME/lib/jibx-bind.jar binding.xml
In questo modo vengono generate delle classi aggiuntive che devono essere incluse nel nostro programma per utilizzare questo binding. Vediamo ora un programma che prova quello che abbiamo fatto finora
package com.javastaff.testjibx; import java.io.FileInputStream; import org.jibx.runtime.BindingDirectory; import org.jibx.runtime.IBindingFactory; import org.jibx.runtime.IUnmarshallingContext; public class Test { public static void main(String[] args) throws Exception { IBindingFactory bfact = BindingDirectory.getFactory(Persona.class); IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); Object obj = uctx.unmarshalDocument( new FileInputStream("C:/jibxTest/bind/testservice.xml"), null); Persona persona = (Persona) obj; System.out.println(persona.getNome()); System.out.println(persona.getCognome()); System.out.println(persona.getEmail()); System.out.println(persona.getCodiceFiscale()); System.out.println(persona.getIndirizzo().getVia()); System.out.println(persona.getIndirizzo().getNumeroCivico()); System.out.println(persona.getIndirizzo().getCitta()); System.out.println(persona.getIndirizzo().getCap()); } }
Avviando questo programma vedremo come JiBX riconosce il file XML, lo trasforma in quello che gli abbiamo detto e ci permette di stampare a schermo le informazioni. Bisogna più che altro imparare il modo in cui descrivere a JiBX quello che vogliamo fare, dopo di che identificare il modo in cui possiamo realizzare un mapping è una cosa abbastanza semplice.
Mapping più complessi
Non tutti i mapping che vogliamo realizzare sono così semplici. Magari nel file XML che dobbiamo analizzare alcuni dati sono deifniti come attributi di un tag, altri come valori veri e propri. Proprio per questo attraverso JiBX possiamo definire due diversi modi per recupare i valori durante il parsing
- value-style=”attribute”
- value-style=”element”
Queste definizioni, che possiamo includere a livello globale nel nostro file mapping oppure a livello locale quando stiamo analizzando un particolare tag, ci permettono rispettivamente di recuperare i valori degli attributi e i valori degli elementi. Se ad esempio avessimo avuto il seguente file XML prima
<?xml version="1.0" encoding="ISO-8859-1"?> <SERVICE_RESPONSE> <NAME>Federico</NAME> <SURNAME>Paparoni</SURNAME> <EMAIL>doc at javastaff dot com</EMAIL> <ID>ABCDEFGHILMNO</ID> <INDIRIZZO STREET="VIA ROMA" NUMBER="23" CITY="CASAL DEI PAZZI" CAP="12345"/> </SERVICE_RESPONSE>
il mapping sarebbe stato chiaramente differente perchè i valori sono definiti come attributi del tag INDIRIZZO. La configurazione sarebbe quindi cambiata in questo modo
<?xml version="1.0" encoding="ISO-8859-1"?> <binding> <mapping name="SERVICE_RESPONSE"class
=
"com.javastaff.testjibx.Persona"
> <value name="NAME" field="nome"/> <value name="SURNAME" field="cognome"/> <value name="EMAIL" field="email"/> <value name="ID" field="codiceFiscale"/> <structure name="INDIRIZZO" field="indirizzo" value-style="attribute"> <value name="STREET" field="via"/> <value name="NUMBER" field="numeroCivico"/> <value name="CITY" field="citta"/> <value name="CAP" field="cap"/> </structure> </mapping> </binding>
In questo caso abbiamo detto a JiBX che il tag INDIRIZZO deve essere associato alla variabile indirizzo di Persona e che inoltre i valori devono essere reperiti tra gli attributi, settando il relativo value-style=”attribute”. Ma JiBX non finisce qui, possiamo gestire ad esempio anche collezioni di dati simili attraverso le classiche List di Java. Immaginiamo che nel nostro XML oltre una parte fissa, vengano ripetuti dei tag uguali con valori differenti (il riepilogo di un ordine ad esempio con differenti item).
In questo caso possiamo realizzare il binding utilizzando le collection, definendo come deve essere gestito l’elemento tipico di questa collezione e poi lato Java avremo un List con tutti gli oggetti valorizzati. Esistono poi molte altre configurazioni possibili che aumentano di molto le possibilità offerte da questa libreria. Per maggiori informazioni vi rimando all’accurata documentazione presente nel sito del progetto
Commenti recenti