Postat la
26-Jun-2009
ora
07:12 pm
de
[Cristian Manea]
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.... :)