sabato 9 luglio 2011

Gestione di file Xml con JAX-B

Utilizzando la libreria jax-b diventa molto semplice sia la creazione che la lettura di file xml.
Vediamo un pratico esempio di creazione di un file xml che presenti una lista utenti per una applicazione.


CREAZIONE DELLE CLASSI

Il primo e più importante passo da seguire è quello di creare opportunamente una delle classi java. E’ necessario quindi disporre di una versione di java 1.5 o superiore.

La classe che rappresenta l’xml si chiama ListaUtenti e ha al suo interno una proprietà di tipo String nomeApplicazione e una Collection di oggetti di tipo Utente.

package oggetto;
import java.util.ArrayList;
import java.util.Collection;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="listaUsers")
public class ListaUtenti {
 
       private String applicazione;
       private Collection<Utente> listaUtenti;
         @XmlAttribute(name="applicazione",required=true)
       public String getApplicazione() {
             return applicazione;
       }
       public void setApplicazione(String applicazione) {
             this.applicazione = applicazione;
       }
       @XmlElementWrapper(name="elencoUtenti",nillable=true,required=false)
       @XmlElement(name="utente",nillable=true,required=false)
       public Collection<Utente> getListaUtenti() {
             return listaUtenti;
       }
       public void setListaUtenti(Collection<Utente> listaUtenti) {
             this.listaUtenti = listaUtenti;
       }
       public String toString(){
             StringBuffer sb=new StringBuffer();
             sb.append("Lista utenti dell'applicazione "+applicazione);
             sb.append("\n");
             ArrayList<Utente> lista=(ArrayList<Utente>)listaUtenti;
             for(int i=0;i<lista.size();i++){
                    sb.append("********");
                    sb.append(" Utente "+(i+1));
                    sb.append(" ********");
                    sb.append("\n");
                    sb.append(lista.get(i).toString());
                    sb.append("********");
                    sb.append("\n");
             }
             return sb.toString();
      }
}


Vediamo il dettaglio delle annotazioni

@XmlRootElement(name="listaUsers")

Indica il nodo root del documento Xml. Con il parametro name è possibile personalizzare il nome dell’xml, di default altrimenti sarebbe preso il nome della classe.

@XmlAttribute(name="applicazione",required=true)

In questo modo si specifica che la proprietà  “applicazione” sarà mappata come un attributo.

ATTENZIONE:  la proprietà required=”true” ha una funzionalità esclusivamente documentativa e non implica che il campo sarà validato in fase di creazione dell’xml. Per validare l’xml bisogna definire un XML Schema e passarlo agli oggetti  Marshaler ed UnMarshaler utilizzando SchemaFactory. La validazione dell’xml utilizzando l’xml schema sarà oggetto di un successivo post


La collection di oggetti di tipo Utente è annotata in questo modo:

@XmlElementWrapper(name="elencoUtenti",nillable=true,required=false)
@XmlElement(name="utente",nillable=true,required=false)

L’annotazione @XmlElementWrapper è usata per creare dei wrapper per le collection.
L’annotazione  @XmlElement mappa la proprietà del Java Bean ad un elemento xml.


Vediamo adesso il dettaglio della classe Utente:




package oggetto;
import java.sql.Timestamp;
import java.util.Date;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlType(name="utente",propOrder={"username","password","nome","cognome","email","dataNascita","tsInserimento"})
public class Utente {
private String username;
private String password;
private String nome;
private String cognome;
private Date dataNascita;
private String email;
private Timestamp tsInserimento;
@XmlElement(name="user",required=true)
public String getUsername() {
       return username;
}
public void setUsername(String username) {
       this.username = username;
}
@XmlElement(name="password",required=true)
public String getPassword() {
       return password;
}
public void setPassword(String password) {
       this.password = password;
}
@XmlElement(name="nome",required=true)
public String getNome() {
       return nome;
}
public void setNome(String nome) {
       this.nome = nome;
}
@XmlElement(name="cognome",required=true)
public String getCognome() {
       return cognome;
}
public void setCognome(String cognome) {
       this.cognome = cognome;
}
@XmlElement(name="dataNascita",required=true)

public Date getDataNascita() {
       return dataNascita;
}
public void setDataNascita(Date dataNascita) {
       this.dataNascita = dataNascita;
}
@XmlElement(name="email",required=true)
public String getEmail() {
       return email;
}
public void setEmail(String email) {
       this.email = email;
}
@XmlElement(name="timeStampInserimento",required=true)
public Timestamp getTsInserimento() {
       return tsInserimento;
}
public void setTsInserimento(Timestamp tsInserimento) {
       this.tsInserimento = tsInserimento;
}
public String toString(){
       StringBuffer sb=new StringBuffer();
      sb.append("Username: ");
      sb.append(this.username);
      sb.append("\n");
       ……..
       return sb.toString();
}
}


Notiamo che la classe è annotata in questo modo:

@XmlType(name="utente",propOrder={"username","password","nome","cognome","email","dataNascita","tsInserimento"})

L’annotazione @XmlType mappa una classe ad un elemento definito nell’XmlSchema.

propOrder si utilizza per definire un ordinamento personalizzato delle proprietà, altrimenti si segue l’ordine di dichiarazione delle proprietà nella classe.
Si noti che il nome utilizzato all’interno di propOrder è il nome della variabile nella classe, non il name dell’elemento xml specificato in @XmlElement.

Nella classe Utente abbiamo un campo di tipo Timestamp. E’ stato introdotto perché è l’unico campo per cui non funziona automaticamente la conversione in xml; questo perché l’oggetto java.sql.Timestamp non ha un costruttore vuoto.

Per ovviare a questo problema si procede in questo modo:

  1. Si crea una classe con costruttore vuoto che “wrappi” il Timestamp;
  2. Si crea una classe chiamandola package-info.java;

Ecco un esempio di classe adapter:



package oggetto;
import java.sql.Timestamp;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class TimeStampAdapter  extends XmlAdapter<Date, Timestamp> { 

  public Date marshal(Timestamp v) { 
      return new Date(v.getTime()); 
  } 

  public Timestamp unmarshal(Date v) { 
      return new Timestamp( 
          v.getTime()); 
 

















Ed ecco il contenuto della classe package-info.java

@XmlJavaTypeAdapters
   @XmlJavaTypeAdapter(value=TimeStampAdapter.class,type=Timestamp.class)) 
package oggetto; 
 
import java.sql.Timestamp; 
 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;


In questo modo tutti i campi di tipo Timestamp saranno automaticamente rimappati utilizzando la classe TimeStampAdapter prima riportata.

CREAZIONE DELL’XML

Per creare l’xml sono sufficienti poche righe di codice, utilizzando l’oggetto javax.xml.binder.Marshaller .


public static void main(String[] args) {
             try
             {
             File f=new File("output/exportList.xml");
             CreaListaUtentiXml lista=new CreaListaUtentiXml();
             // JAX-B
             JAXBContext jc=JAXBContext.newInstance(ListaUtenti.class);
             Marshaller marsh = jc.createMarshaller();
             marsh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
             FileWriter fw=new FileWriter(f);
             marsh.marshal(lista.generaListaUtenti(), fw);
             fw.flush();
             }
             catch(Exception ex){
                    ex.printStackTrace();
             }
      }


Il settaggio della proprietà Marshaller.JAXB_FORMATTED_OUTPUT serve solo per scopi di formattazione dell’output.

La lista utenti si ottiene dalla classe CreaListaUtentiXml, di seguito per comodità si riporta il listato del metodo generaListaUtenti() .


/**
        * Torna la lista oggetti (in un caso reale qui ci sarà <br>
        * la chiamata a Db)
        * @return
        */
    private ListaUtenti generaListaUtenti(){
       ListaUtenti l=new ListaUtenti();
       l.setApplicazione("anagrafe");
       l.setListaUtenti(getListaUtenti());
       return l;
    }
    private Collection<Utente> getListaUtenti(){
       Collection<Utente> retList=new ArrayList<Utente>();
       // utente 1
       Utente u1=new Utente();
       u1.setCognome("rossi");
       u1.setEmail("rossi@test.it");
       u1.setDataNascita(creaData(20, 4, 1978));
       u1.setNome("mario");
       u1.setPassword("laksjdfejhrkjhre");
       u1.setTsInserimento(new Timestamp(System.currentTimeMillis()));
       u1.setUsername("mrossi");
      
       // utente 2
       Utente u2=new Utente();
       u2.setCognome("bianchi");
       u2.setEmail("bianchi@test.it");
       u2.setDataNascita(creaData(9, 10, 1974));
       u2.setNome("mario");
       u2.setPassword("kejhfrlkwerhjlkjew");
       u2.setTsInserimento(new Timestamp(System.currentTimeMillis()));
       u2.setUsername("mbianchi");
      
       // utente 3
       Utente u3=new Utente();
       u3.setCognome("verdi");
       u3.setEmail("verdi@test.it");
       u3.setDataNascita(creaData(9, 10, 1974));
       u3.setNome("mario");
       u3.setPassword("9083218301jkhdkjhadskjhd");
       u3.setTsInserimento(new Timestamp(System.currentTimeMillis()));
       u3.setUsername("verdi");
       // aggiungo a lista
       retList.add(u1);
       retList.add(u2);
       retList.add(u3);
       return retList;
      
    }
    private  Date creaData(int giorno,int mese,int anno){
        Calendar c=Calendar.getInstance();
        c.set(Calendar.YEAR, anno);
        c.set(Calendar.MONTH, mese-1);
        c.set(Calendar.DAY_OF_MONTH, giorno);
        return c.getTime();
    }

Il risultato  prodotto è il seguente:




<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<listaUsers applicazione="anagrafe">
    <elencoUtenti>
        <utente>
            <user>mrossi</user>
            <password>laksjdfejhrkjhre</password>
            <nome>mario</nome>
            <cognome>rossi</cognome>
            <email>rossi@test.it</email>
            <dataNascita>1978-04-20T19:42:06.640+01:00</dataNascita>
            <timeStampInserimento>2011-07-09T19:42:06.640+02:00</timeStampInserimento>
        </utente>
        <utente>
            <user>mbianchi</user>
            <password>kejhfrlkwerhjlkjew</password>
            <nome>mario</nome>
            <cognome>bianchi</cognome>
            <email>bianchi@test.it</email>
            <dataNascita>1974-10-09T19:42:06.640+01:00</dataNascita>
            <timeStampInserimento>2011-07-09T19:42:06.640+02:00</timeStampInserimento>
        </utente>
        <utente>
            <user>verdi</user>
            <password>9083218301jkhdkjhadskjhd</password>
            <nome>mario</nome>
            <cognome>verdi</cognome>
            <email>verdi@test.it</email>
            <dataNascita>1974-10-09T19:42:06.640+01:00</dataNascita>
            <timeStampInserimento>2011-07-09T19:42:06.640+02:00</timeStampInserimento>
        </utente>
    </elencoUtenti>
</listaUsers>




























LETTURA DELL’XML


Per leggere l’xml si procede in maniera analoga alla scrittura dell’xml, utilizzando la classe
javax.xml.binder.Unmarshaller.



public static void main(String[] args) {
             try
             {
                           File f=new File("output/exportList.xml");
             if(f.exists()){
             JAXBContext jc=JAXBContext.newInstance(ListaUtenti.class);
             Unmarshaller um = jc.createUnmarshaller();
             ListaUtenti l=(ListaUtenti)um.unmarshal(f);
             System.out.println(l);
                           }
             else
              {
              System.err.println("Attenzione, il file non esiste!!!");
             }
            }
             catch(Exception ex){
                    ex.printStackTrace();
             }
       }




Nessun commento:

Posta un commento