Diferencia entre revisiones de «XStream»

De Dos Ideas.
Saltar a: navegación, buscar
 
(No se muestran 4 ediciones intermedias de 3 usuarios)
Línea 1: Línea 1:
 +
[[Category:Java]]
 +
 
XStream es una libreria [[Java]] para la serializacion y deserealizacion de objetos a XML (o también [[JSON]]).
 
XStream es una libreria [[Java]] para la serializacion y deserealizacion de objetos a XML (o también [[JSON]]).
 
  
 
==Encoding del XML==
 
==Encoding del XML==
Línea 6: Línea 7:
  
 
Para hacer esto basta programar:
 
Para hacer esto basta programar:
<pre>
+
<code java>
 
     private static final String ENCODING = "ISO-8859-1";
 
     private static final String ENCODING = "ISO-8859-1";
  
Línea 21: Línea 22:
 
     osw.close();
 
     osw.close();
 
     os.close();
 
     os.close();
</pre>
+
</code>
  
 
La variable ENCODING puede tener alguno de los nombres de los charset estándares, o incluso algunos encoding no comunes.
 
La variable ENCODING puede tener alguno de los nombres de los charset estándares, o incluso algunos encoding no comunes.
Línea 30: Línea 31:
  
 
De esta forma:
 
De esta forma:
<pre>
+
<code java>
 
     private static final String ENCODING = "ISO-8859-1";
 
     private static final String ENCODING = "ISO-8859-1";
  
Línea 46: Línea 47:
 
     xml.append(header);
 
     xml.append(header);
 
     xml.append(os.toString());
 
     xml.append(os.toString());
</pre>
+
</code>
  
 
Noten que creamos el encabezado para el XML, indicando el encoding que usaremos. Luego, concatenamos este encabezado al xml resultante.
 
Noten que creamos el encabezado para el XML, indicando el encoding que usaremos. Luego, concatenamos este encabezado al xml resultante.
Línea 55: Línea 56:
 
Con XStream cuando serializamos una clase los tags del XML generado quedan con el nombre de los atributos de esta clase. Por ejemplo, aca vemos como serializamos el siguiente DTO compuesto:
 
Con XStream cuando serializamos una clase los tags del XML generado quedan con el nombre de los atributos de esta clase. Por ejemplo, aca vemos como serializamos el siguiente DTO compuesto:
 
===Los objetos a serializar===
 
===Los objetos a serializar===
<pre>
+
<code java>
 
  public class PersonaDTO {
 
  public class PersonaDTO {
  
Línea 72: Línea 73:
 
     // Getters y Setters
 
     // Getters y Setters
 
  }
 
  }
</pre>
+
</code>
  
 
===Serialización===
 
===Serialización===
<pre>
+
<code java>
 
  import com.thoughtworks.xstream.XStream;
 
  import com.thoughtworks.xstream.XStream;
  
Línea 84: Línea 85:
 
     }
 
     }
 
  }
 
  }
</pre>
+
</code>
  
 
===XML resultante===
 
===XML resultante===
 
Lo cual genera el siguiente XML:
 
Lo cual genera el siguiente XML:
 
+
<code xml>
 
  <test.PersonaDTO.java>
 
  <test.PersonaDTO.java>
 
   <identidad>Juancito</identidad>
 
   <identidad>Juancito</identidad>
Línea 97: Línea 98:
 
   </documentoIdentidad>
 
   </documentoIdentidad>
 
  </test.PersonaDTO.java>
 
  </test.PersonaDTO.java>
 
+
</code>
  
 
Es posible cambiar los nombres de los atributos en el XML utilizando los alias que provee XStream.
 
Es posible cambiar los nombres de los atributos en el XML utilizando los alias que provee XStream.
Línea 111: Línea 112:
 
En las clases a serializar hay que poner sobre el atributo (o clase) la annotation con el nombre que queremos que tenga una vez serializado. Ejemplo:
 
En las clases a serializar hay que poner sobre el atributo (o clase) la annotation con el nombre que queremos que tenga una vez serializado. Ejemplo:
  
<pre>
+
<code java>
 
  @XStreamAlias("Persona")
 
  @XStreamAlias("Persona")
 
  public class PersonaDTO {
 
  public class PersonaDTO {
Línea 137: Línea 138:
 
     // Getters y Setters
 
     // Getters y Setters
 
  }
 
  }
</pre>
+
</code>
  
 
===Activación de anotaciones===
 
===Activación de anotaciones===
 
En el codigo que invoca a XStream se agrega para que procese las annotations, pasandole el .class de la clase que contiene las annotations.
 
En el codigo que invoca a XStream se agrega para que procese las annotations, pasandole el .class de la clase que contiene las annotations.
<pre>
+
<code java>
 
  public class XStreamConAnnotation {
 
  public class XStreamConAnnotation {
  
Línea 151: Línea 152:
 
     }
 
     }
 
  }
 
  }
</pre>
+
</code>
  
 
También es posible activar clase-por-clase el uso de anotaciones, con una línea similar a
 
También es posible activar clase-por-clase el uso de anotaciones, con una línea similar a
Línea 157: Línea 158:
  
 
===XML resultante===
 
===XML resultante===
 
+
<code xml>
 
  <Persona>
 
  <Persona>
 
   <nombre>Juancito</nombre>
 
   <nombre>Juancito</nombre>
Línea 166: Línea 167:
 
   </documento>
 
   </documento>
 
  </Persona>
 
  </Persona>
 +
</code>
 +
 +
==Namespaces==
 +
Es muy común con la utilización de Web Services que se tenga que procesar un xml que tiene definido un namespace. Por ejemplo:
 +
 +
<code xml>
 +
<dosideas:Persona xmlns:dosideas="http://www.dosideas.com/wsdl/buscarClientes">
 +
<nombre>Juancito</nombre>
 +
<edad>16</edad>
 +
</dosideas:body>
 +
</code>
 +
 +
Si se quiere mapear el ejemplo anterior con la clase PersonaDTO (definida en otro ejemplo anteriormente), se deberá colocar el alias @XStreamAlias("'''dosideas:'''Persona"). Si solo se coloca @XStreamAlias("Persona"), XStream no sabra contra que clase mapear "dosideas:Persona" ya que desconoce los namespaces.
 +
 +
Como el namespace puede cambiar a gusto del consumidor (si es un Web Service por ejemplo), se deberá contar con algo mas genérico. Para solucionar este inconveniente se utiliza el StaxDriver que provee XStream, el cual permite especificar un map de QNames.
 +
 +
Un QName  permite identificar un elemento o atributo de xml y tiene 3 componentes:
 +
; Namespace URI : la definicion del namespace. En el ejemplo corresponde a ''xmlns:dosideas="ht..."''
 +
; local part : el nombre del tag. En el ejemplo corresponde a ''Persona''
 +
; prefix : el prefijo. En el ejemplo corresponde a ''dosideas''
 +
 +
Como se puede observar, lo que varia es el prefijo. Entonces se debe crear un QName dejando el prefijo en blanco. El código resultante para el ejemplo seria el siguiente:
 +
 +
<code java>
 +
QNameMap qnameMap = new QNameMap();
 +
QName qname = new QName("http://www.dosideas.com/wsdl/buscarClientes",
 +
                        "Persona");
 +
qnameMap.registerMapping(qname, PersonaDTO.class);
 +
XStream xStream = new XStream(new StaxDriver(qnameMap));
 +
</code>
  
 
==Conversores==
 
==Conversores==
Línea 171: Línea 202:
 
Entre los conversores que tiene xstream se destacan: String, File, Collections, arrays, and Dates. En la página oficial de xstream se encuentra [http://xstream.codehaus.org/converters.html la lista de todos los conversores].   
 
Entre los conversores que tiene xstream se destacan: String, File, Collections, arrays, and Dates. En la página oficial de xstream se encuentra [http://xstream.codehaus.org/converters.html la lista de todos los conversores].   
  
==Ejemple de uso DateConverter==
+
==Ejemplo de uso DateConverter==
 
El DateConverter en un conversor para el tipo de objeto java.util.Date.
 
El DateConverter en un conversor para el tipo de objeto java.util.Date.
 
Para usarlo debemos crear una nueva instancia indicando los formatos de fechas aceptados
 
Para usarlo debemos crear una nueva instancia indicando los formatos de fechas aceptados
Línea 186: Línea 217:
 
Supongamos que queremos convertir la siguiente clase usando el DateConverter:
 
Supongamos que queremos convertir la siguiente clase usando el DateConverter:
  
<pre>
+
<code java>
 
  public class PersonaDTO {
 
  public class PersonaDTO {
  
Línea 194: Línea 225:
 
     // Getters y Setters
 
     // Getters y Setters
 
  }
 
  }
</pre>
+
</code>
  
 
El formato esperado de la fecha será 'ddMMyyyy', el siguiente código muestra como crear y regisrar el DateConverter.
 
El formato esperado de la fecha será 'ddMMyyyy', el siguiente código muestra como crear y regisrar el DateConverter.
  
<pre>
+
<code java>
 
class Main {
 
class Main {
 
     public static void main( String args[] ) {
 
     public static void main( String args[] ) {
Línea 218: Línea 249:
 
         }
 
         }
 
     }
 
     }
</pre>
+
</code>
 +
 
 
===XML resultante===
 
===XML resultante===
<pre>
+
<code xml>
 
<Persona>
 
<Persona>
 
   <identificacion>dos ideas</identificacion>
 
   <identificacion>dos ideas</identificacion>
 
   <fechaNacimiento>29112000</fechaNacimiento>
 
   <fechaNacimiento>29112000</fechaNacimiento>
 
</Persona>
 
</Persona>
</pre>
+
</code>
 
 
 
 
 
 
  
 
==Ver también==
 
==Ver también==

Revisión actual del 15:56 26 ago 2009


XStream es una libreria Java para la serializacion y deserealizacion de objetos a XML (o también JSON).

Encoding del XML

XStream utiliza Writers para generar los XML, usando el encoding por default de la plataforma. Para cambiarlo, es necesario proveer a XStream con un Writer propio, que contenga el encoding deseado.

Para hacer esto basta programar:

   private static final String ENCODING = "ISO-8859-1";
   .....
   OutputStream os = new ByteArrayOutputStream();
   OutputStreamWriter osw = new OutputStreamWriter(os, ENCODING);
   XStream xstream = new XStream();
   xstream.toXML(objetoParaTransformar, osw);
   String xml = os.toString();
   osw.close();
   os.close();

La variable ENCODING puede tener alguno de los nombres de los charset estándares, o incluso algunos encoding no comunes.

El XML con el encabezado correspondiente

XStream no genera el encabezado de los XML, donde se indica el encoding usado. Es necesario entonces que lo generemos nosotros antes de devolver el xml.

De esta forma:

   private static final String ENCODING = "ISO-8859-1";
   .....
   XStream xstream = new XStream();
   OutputStream os = new ByteArrayOutputStream();
   OutputStreamWriter osw = new OutputStreamWriter(os, ENCODING);
   xstream.toXML(objetoParaTransformar, osw);
   String header = "<?xml version=\"1.0\" encoding=\"" + osw.getEncoding() + "\"?>\n";
   StringBuffer xml = new StringBuffer();
   xml.append(header);
   xml.append(os.toString());

Noten que creamos el encabezado para el XML, indicando el encoding que usaremos. Luego, concatenamos este encabezado al xml resultante.

Ejemplo de uso

El Tutorial de XStream tiene un ejemplo claro y simple de uso.

Con XStream cuando serializamos una clase los tags del XML generado quedan con el nombre de los atributos de esta clase. Por ejemplo, aca vemos como serializamos el siguiente DTO compuesto:

Los objetos a serializar

public class PersonaDTO {
    private String identidad;
    private Long edad;
    private DocumentoDTO documentoIdentidad;
    // Getters y Setters
}


public class DocumentoDTO {
    private Long numero;
    private String tipo;
    // Getters y Setters
}

Serialización

import com.thoughtworks.xstream.XStream;
public class XStreamConAnnotation {
    public String toXml(PersonaDTO dto) {
        XStream xstream = new XStream();
        return (String) xstream.toXML(dto);
    }
}

XML resultante

Lo cual genera el siguiente XML:

<test.PersonaDTO.java>
  <identidad>Juancito</identidad>
  <edad>16</edad>
  <documentoIdentidad>
    <numero>35123125</numero>
    <tipo>DNI</tipo>
  </documentoIdentidad>
</test.PersonaDTO.java>

Es posible cambiar los nombres de los atributos en el XML utilizando los alias que provee XStream.

Ejemplo de uso con anotaciones

Desde la version 1.3 de [XStream] se agrego como funcionalidad la posibilidad de usar Annotations en lugar de los alias para establecer el mapeo entre las clases, los atributos y los tags de los XML.

Con esta nueva funcionalidad para modificar algun tag hay que hacer 2 cosas

  1. Anotar la clase
  2. Activar el uso de anotaciones al usar XStream

Anotación de la clase

En las clases a serializar hay que poner sobre el atributo (o clase) la annotation con el nombre que queremos que tenga una vez serializado. Ejemplo:

@XStreamAlias("Persona")
public class PersonaDTO {
    @XStreamAlias("nombre")
    private String identidad;
    @XStreamAlias("años")
    private Long edad;
    @XStreamAlias("documento")
    private DocumentoDTO documentoIdentidad;
    // Getters y Setters
}
public class DocumentoDTO {
    @XStreamAlias("numeroDocumento")
    private Long numero;
    @XStreamAlias("tipoDocumento")
    private String tipo;
    // Getters y Setters
}

Activación de anotaciones

En el codigo que invoca a XStream se agrega para que procese las annotations, pasandole el .class de la clase que contiene las annotations.

public class XStreamConAnnotation {
    public String toXml(PersonaDTO dto) {
        XStream xstream = new XStream();
        xstream.autodetectAnnotations(true);
        return (String) xstream.toXML(dto);
    }
}

También es posible activar clase-por-clase el uso de anotaciones, con una línea similar a

 xstream.processAnnotations(PersonaDTO.class);

XML resultante

<Persona>
  <nombre>Juancito</nombre>
  <años>16</años>
  <documento>
    <numeroDocumento>35123125</numeroDocumento>
    <tipoDocumento>DNI</tipoDocumento>
  </documento>
</Persona>

Namespaces

Es muy común con la utilización de Web Services que se tenga que procesar un xml que tiene definido un namespace. Por ejemplo:

<dosideas:Persona xmlns:dosideas="http://www.dosideas.com/wsdl/buscarClientes">

<nombre>Juancito</nombre>
<edad>16</edad>

</dosideas:body>

Si se quiere mapear el ejemplo anterior con la clase PersonaDTO (definida en otro ejemplo anteriormente), se deberá colocar el alias @XStreamAlias("dosideas:Persona"). Si solo se coloca @XStreamAlias("Persona"), XStream no sabra contra que clase mapear "dosideas:Persona" ya que desconoce los namespaces.

Como el namespace puede cambiar a gusto del consumidor (si es un Web Service por ejemplo), se deberá contar con algo mas genérico. Para solucionar este inconveniente se utiliza el StaxDriver que provee XStream, el cual permite especificar un map de QNames.

Un QName permite identificar un elemento o atributo de xml y tiene 3 componentes:

Namespace URI 
la definicion del namespace. En el ejemplo corresponde a xmlns:dosideas="ht..."
local part 
el nombre del tag. En el ejemplo corresponde a Persona
prefix 
el prefijo. En el ejemplo corresponde a dosideas

Como se puede observar, lo que varia es el prefijo. Entonces se debe crear un QName dejando el prefijo en blanco. El código resultante para el ejemplo seria el siguiente:

QNameMap qnameMap = new QNameMap(); QName qname = new QName("http://www.dosideas.com/wsdl/buscarClientes",

                       "Persona");

qnameMap.registerMapping(qname, PersonaDTO.class); XStream xStream = new XStream(new StaxDriver(qnameMap));

Conversores

La librería xstream nos provee de una serie de conversores. La función de un conversor es la de convertir tipos de objetos particulares en xml o construir los mismos a partir de un xml. Entre los conversores que tiene xstream se destacan: String, File, Collections, arrays, and Dates. En la página oficial de xstream se encuentra la lista de todos los conversores.

Ejemplo de uso DateConverter

El DateConverter en un conversor para el tipo de objeto java.util.Date. Para usarlo debemos crear una nueva instancia indicando los formatos de fechas aceptados El constructor recibe dos parámetros:

String defaultFormat: formato de la fecha que sera tomado por default.

String[] acceptableFormats: Array con todos los formatos de fecha aceptables.

Los formatos de la fecha esperados son los patrones de SimpleDateFormat.

El funcionamiento se describe así: cuando xstream encuentra un tag que esta mapeado a un objeto del tipo java.util.Date usara el conversor, el mismo tratará de convertir el tag usando el formato default, si falla ira probando los otros formatos aceptados hasta encontrar el adecuado, de no encontrarlo lanzará una ConversionException. Si se se esta convirtiendo un objeto Date a xml siempre se usara el formato default para convertirlo.

Supongamos que queremos convertir la siguiente clase usando el DateConverter:

public class PersonaDTO {
    private String identidad;
    private Date fechaNacimiento;
    // Getters y Setters
}

El formato esperado de la fecha será 'ddMMyyyy', el siguiente código muestra como crear y regisrar el DateConverter.

class Main {

   public static void main( String args[] ) {
       //objetoq ue se convertira a xml usando DateConverter
       PersonaDTO persona = new PersonaDTO();
       persona.setIdentidad("dos ideas");
       persona.setFechaNacimiento(new Date());
       
       //se crea una nueva instancia de DateConverter con los formatos requeridos
       String defaultFormat = "ddMMyyyy"
       String[] acceptableFormats = new String[]{"yyyyMM"};
       DateConverter dateConverter = new DateConverter(defaultFormat, acceptableFormats );
       
       //ya instanciamos nuestro DateConverter, falta registralo 
       XStream xstream = new XStream();
       xstream.registerConverter(dateConverter);
       System.out.println(xstream.toXML(persona);
       }
   }

XML resultante

<Persona>

 <identificacion>dos ideas</identificacion>
 <fechaNacimiento>29112000</fechaNacimiento>

</Persona>

Ver también