X-stream: xml è facile !

xml_at_workSalve a tutti…ebbene sì…si ricomincia. Siccome è passato un pò di tempo dall’ultimo post, inizierò a scrivere così come se niente fosse…così nessuno se né accorgerà :P  ! Sono alle prese con lo sviluppo di un’applicazione web, che fa uso di XML per la serializzazione dei dati. L’applicazione è scritta in Java, usa Spring come framework di appoggio. La parte fondamentale come dicevo, consiste nella serializzazione dei dati in XML. La struttura XML che deve essere serializzata non è molto complessa, ma neanche troppo semplice…per cui al primo impatto, ho deciso di non appoggiarmi sulle classiche librerie messe a disposizione da Java (xerces) o quelle presenti di default nelle API (javax.xml.parser).
Sono andato così alla ricerca in rete di qualcosa che potesse essermi utile, cercavo qualcosa che fosse facile da usare e al tempo stesso leggero, in modo tale da non appesantire l’applicazione. Ho trovato così XStream, una libreria che permette di serializzare oggetti in XML e viceversa. Il viceversa nel mio caso è fondamentale, dal momento che se possibile inizializzare una struttura dati di oggetti senza dover, materialmente, navigare l’XML mi ha aiutato molto.
Non mi soffermerò molto nel descrivere le caratteristiche della libreria, sopra come avrete notato ho linkato l’URL quindi potete fare da voi…mi concentrerò su qualche feature che mi è sembrata interessante e descriverò qualche esempio pratico.
La creazione di un file XML a partire da un oggetto Java è molto semplice, si parte dalla creazione e inizializzazione dell’oggetto stesso, dopo di ché si procedere richiamando un metodo statico che provvede alla generazione (serializzazione) del file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Blog {
  private String name;
  private String author;
  private Contacts contacts;
  /* getter&setter + constructor */
}
 
public class Contacts {
  private String email;
  private String url;
  /* getter&setter + constructor */
}
 
XStream xstream = new XStream();
XStream xstream = new XStream(new DomDriver());
 
/* GLi alias rendono la serializzazione più chiara */
xstream.alias("person", Blog.class);
xstream.alias("phonenumber", Contacts.class);
 
Blog blog = new Blog("DevMe", "mulp");
blog.setContacts(new Contacts("mulp@devme.it", "http://www.devme.it"));
String xml = xstream.toXML(blog);
<blog>
    <name>DevMe</name>
    <author>mulp</author>
    <contacts>
    	<email>mulp@devme.it</email>
    	<url>http://www.devme.it</url>
    </contacts>
</blog>

Al contrario, dando in input l’XML prodtto, si ottiene l’oggetto inizializzato:

1
Blog blog = (Blog)xstream.fromXML(xml);

L’esempio di prima dimostra la facilità e la flessibilità d’uso della libreria XStream. Unico particolare degno di nota è il fatto di poter definire degli alias per le classi che permette poi, in fase di serializzazione di poter generare tag coincisi dal nome uguale al nome della variabile membro, a meno che non si chieda di cambiarlo. Per intenderci, se non avessi definito gli alias otterei come tag il nome completo della classe per il tag blog assieme al nome del package, nell’esempio quello di default.

XStream usa il meccanimo delle Annotations per definire gli alias, rendendo così la definizione decisamente più pratica. Vediamo un esempio di codice che non definisce alias:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package it.devme.music;
 
public class Police {
    private String songTitle;
    public Police(String songTitle) {
        this.songTitle = songTitle;
    }
}
 
package it.devme.music;
public class JukeBox {
    public static void main(String[] args) {
        XStream stream = new XStream();
	Police song = new Police("Message in a bottle");
	System.out.println(stream.toXML(msg));
    }
}

L’esecuzione del codice produce il seguente XML:

1
2
3
    <it.devme.music.Police>
        <songTitle>Message in a bottle</songTitle>
    </it.devme.music.Police>

Come si può notare, senza l’utilizzo degli alias la serializzazione in XML non è coincisa, in particolare il nome della classe Persona eredita l’intero percorso del suo package di appartenenza. Definiamo ora gli alias usando le Annotations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package it.devme.music;
 
@XStreamAlias("police-songography")
public class Police {
    @XStreamAlias("song")
    private String songTitle;
    public Police(String songTitle) {
        this.songTitle = songTitle;
    }
}
 
package it.devme.music;
public class JukeBox {
    public static void main(String[] args) {
        XStream stream = new XStream();
	Police song = new Police("Message in a bottle");
	System.out.println(stream.toXML(msg));
    }
}

L’esecuzione del codice produce il seguente XML:

1
2
3
    <police-songography>
        <song>Message in a bottle</song>
    </police-songography>

Notate ora come il file XML è più chiaro e come il nome dei tag non dipende strettamente dai nomi delle classi e/o delle variabili membro, ma dagli alias definiti all’interno della classe stessa.

Come ultima cosa volevo soffermarmi su un’altra caratteristica di questa libreria, i Converter. Questo meccanismo da la possibilità di poter gestire in fase di serializzazione/deserializzazione l’esatta elaborazione che deve essere svolta in modo tale da avere una corretta esecuzione delle procedure. Per poter scrivere il proprio Converter è necessario implementare l’interfaccia Converter ed implementare i metodi proposti:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package it.devme.music;
public class PoliceConverter implements Converter {
    public boolean canConvert(Class clazz) {
        return false;
    }
 
    public void marshal(Object value, HierarchicalStreamWriter writer,
                        MarshallingContext context) {
        }
 
    public Object unmarshal(HierarchicalStreamReader reader,
                        UnmarshallingContext context) {
        return null;
    }
}

Il metodo canConvert verifica l’applicabilità del converter rispetto alla classe che si desidera pre/post elaborare. Il metodo marshal è una pre elaborazione, mentre unmurshal è una post elaborazione. I casi d’uso di un Converter variano dai più semplici, in cui si applica una trasformazione al tipo di dato che dovrà essere serializzato (si pensi ad esempio ad una data in formato millisecondi da trasformare in gg/mm/aaaa), ai più complessi in cui è necessario elaborare un nodo complesso contenente sottoalberi, ovviamente in entrambe le operazioni di serializzazione/deserializzazione. Vi rimando al tutorial sui Converter per gli esempi del caso.

See U on next post, enjoy !

WordPress Themes