Cu siguranta, ne-am pus toti problema cel putin odata cum sa persistam continutul claselor noastre in XML (human readable, nu serializarea “standard” din java), si cum sa reconstruim continutul acelei clase in un obiect in programul nostru.

Aplicabilitatile sunt multiple, cea mai comuna este generarea si citirea de file xml transmise intre aplicatii. Cu siguranta veti fi de acord ca modalitatea “veche” de citire a unui file xml utilizand modelul DOM este cel putin “outdated” pentru majoritatea cazurilor. Singurul motiv pentru care as vrea sa mai utilizez un model specializat pentru asta ar fi pentru cazurile cu structuri de date extrem de mari, in aplicatii in care eventual performanta este extrem de importanta incat sa merite “miimea de secunda” in minus cu pretul timpului de dezvoltare mai mare si al pierderii flexibilitatii si al elegantei in dezvoltare.

Modalitatea “ok” care trebuie utilizata (si pentru viteza de dezvoltare, si mai ales pentru claritate, eleganta si usurinta in modificare), este “modelarea” in clase a structurilor de date cu care vom lucra, arborescente sau nu, la orice nivel de complexitate. Va urma ca apoi sa “deserializam” continutul fisierului xml in un obiect instanta a clasei noastre, respectiv sa generam continutul xml “serializand” obiectul in fisier (sau orice alt mediu).

O modalitate simpla, rapida si flexibila, pe care am gasit-o extrem de usor de utilizat, si mai ales bine documentata (stim cu totii care lucreaza cu java ca asta este unul dintre “pacatele” capitale....) este frameworkul open-source Xstream: “XStream is a simple library to serialize objects to XML and back again. ... is easier to read for humans and more compact than native Java serialization”

Nu o sa stau acum sa fac o prezentare foarte tehnica, pentru asta gasiti tot ce va trebuie (cum spuneam, este foarte bine documentata) la adresa http://xstream.codehaus.org/ . Voi da insa un exemplu simplu “get started” care se poate aplica insa in 99% din cazurile intalnite “in viata reala” (ca si cand noi, software-istii, am avea viata reala... :) ).

Problema mea era, in cateva cuvinte, destul de simpla:

  •    Pe o structura de date oarecum complexa (un model de obiecte), aveam nevoie de o reprezentare xml la un anumit moment dat pentru a il putea “stoca” pentru mai tarziu si a compara eventuale variatii. Nu vreau sa trebuiasca sa scriu cod in cazul modificarii clasei in afara de definitia efectiva a clasei, si nu vreau sa intru in prea multe detalii care nu tin de partea de business a aplicatiei. Solutia:

public class Application  {

.......................

    private static                XStream xStream = null;

.......................

    private String getXMLSerialized()

    {

        if(xStream == null)

        {

           //use singleton xstream

           xStream = new XStream();                     

           xStream.autodetectAnnotations(true);

        }

           return(xStream.toXML(this));        

    }

Practic... pentru a serializa am avut nevoie de 2 linii de cod... Una pentru instantiere, una pentru a face serializarea (in cazul nostru in un string, dar metoda toXML are supraincarcari pentru a putea scrie direct intr-un stream...)
In plus, evident se vede am folosit un singleton (nesincronizat) pentru instantierea clasei xstream, ca doar stim sa programam... Nu?

  • Nu vroiam sa serializez toate datele din structura mea de date, ci doar partea care pentru era semnificativa pentru carintele aplicatiei

public class Application  {

    private java.lang.Long        idApp;

    private String name;

    private String testResult;

    private Date   testResultDate;

    private String testResultNotes;

    private Phase  phase;

    // service properties

    @XStreamOmitField

    private int internalId;

    @XStreamOmitField

    private int internalCrId;

    @XStreamOmitField

    private ActionEnum action = ActionEnum.None;

    @XStreamOmitField

    private boolean  isActive = true;

    @XStreamOmitField

    private String hashedValue = "";

    @XStreamOmitField

    private static                XStream xStream = null;

....................................

}

Foarte simplu... ajunge sa marcati variabilele pe care nu vreti sa le serialiazati in rezultatul xml cu un “annotation”:  @XstreamOmitField.
Important: pentru a indica faptul ca dorim folosirea de “annotations” de catre frameworkul nostru, trebuie sa o facem explicit: xStream.autodetectAnnotations(true);

  • Deserializarea nu ma interesa, dar voi da un exemplu minimal pentru a completa cercul. Trebuie doar sa informam framework-ul ca aliasul “application” se mapeaza in clasa Application. Chemam xStream.fromXML – cu overloadul dorit pentru sursa de unde dorim exact serializarea. Si cam atat..

xStream.alias("application",Application.class)        

Application myApp = (Application) xStream.fromXML(string)

Xstream este evident mult mai complex, si extrem de flexibil pentru mai toate scenariile pe care ni le putem imagina. De exemplu... ca tot vorbeam de performanta... se poate folosi  impreuna cu Xstream un ultraperformant Xml Pull Parser (pe scurt XPP)  care implementeaza specificatiile XmlPull API..

Deja vorbesc chineza? Ma opresc.... :)