lundi 27 mai 2013

Modifier le rendu d'une liste de string avec XStream en utilisant un converter

Continuons avec la classe Toto contient une liste de String dont le rendu est le suivant :
<liste__Produit>
  <string>truc</string>
  <string>bidule</string>
</liste__Produit>

Plutôt que d'avoir une suite de balise string, il serait souhaitable d'avoir une balise part.
Dans la documentation, il existe l'annotation @XStreamImplicit.
Il y a deux paramètres : itemFieldName et keyFieldName.
Le premier indique l'alias de la collection et le deuxième sert pour les type Map.
Avec le code suivant :
@XStreamAlias("listeProduit")
@XStreamImplicit(itemFieldName="part")
public List titi = new ArrayList() ;

Le résultat est à présent :
<produit>
  <id>1</id>
  <part>truc</part>
  <part>bidule</part>
  <dateEnvoie>2013-03-01 10:12:04.306 UTC</dateEnvoie>
</produit>

La liste est donc mise à plat avec une suite d'entrée.
Si il est désiré d'avoir une balise parente, il va falloir passer par un converter maison.
Voici l'annotation :
@XStreamAlias("listeProduit")
@XStreamConverter(value=ListToStringXStreamConverter.class, strings={"part"}) 
public List titi = new ArrayList() ;

Avant de continuer, voyons un peu le principe.
value indique le nom de la classe de conversion.
strings est quant à lui disponible dans l'annotation pour des besoins annexes. Ce paramètre sera transmis au constructeur. D'autres champs sont mis à disposition et peuvent être exploités pour des besoins spécifiques comme types qui permet de contenir des classes.
// Come from http://stackoverflow.com/questions/1791178/customising-serialisation-of-java-collections-using-xstream
public class ListToStringXStreamConverter implements Converter {

private String alias;

public ListToStringXStreamConverter(String alias) {
    super();
    this.alias = alias;
}

@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
    return true;
}

@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {

    @SuppressWarnings("unchecked")
    List list = (List)source;

    for (String string : list) {
        writer.startNode(alias);
        writer.setValue(string);
        writer.endNode();
    }
}

@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    throw new UnsupportedOperationException("ListToStringXStreamConverter does not offer suport for unmarshal operation");
}

Et mainteant, voici le rendu :
<produit>
  <id>1</id>
  <listeProduit>
    <part>truc</part>
    <part>bidule</part>
  </listeProduit>
  <dateEnvoie>2013-03-01 10:25:19.10 UTC</dateEnvoie>
</produit>

Ce qui est fait, c'est de remplacer le composant qui affiche une liste par le notre.
Par défaut, XStream écrit l'alias du champs et ensuite le converter écrit les données dans le flux. Pour cela, il prend en paramètre le nom du noeud à créer ("part").

lundi 20 mai 2013

Modifier le rendu d'une balise XML avec XStream en utilisant un converter

Toujours en utilisant le même exemple, la classe Toto contient une date dont le rendu est le suivant :
<date__Envoie>2013-02-28 17:01:29.669 UTC</date__Envoie>

Afin de personnaliser l'affichage de la date, il est possible via une annotation d'indiquer a XStream de ne pas utiliser le rendu standard mais un rendu personnalisé.
Il est donc nécessaire d'ajouter l'annotation suivant au champ dateEnvoie (en-dessous de l'annotation alias) :
@XStreamConverter(value=MyDateConverter.class)

Dans le cas d'une date (mais aussi pour une String, Integer...), il s'agit de remplacer le comportement de la classe com.thoughtworks.xstream.converters.basic.DateConverter.
Cette classe hérite de la classe com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter.
Il est simplement nécessaire de redéfinir les méthodes :
public class MyDateConverter extends AbstractSingleValueConverter {
    // Indique si cette classe prend en charge la conversion
    @Override
    public boolean canConvert(Class type) {
        return type.equals(java.util.Date.class);
    }

    // Transforme la valeur XML en Java
    @Override
    public Object fromString(String str) {
        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd") ;
        
        Date dateStr = null ; 
            
        try {
            dateStr = sdf.parse(str) ;
        } catch (ParseException e) {
            // Nothing
        }
         
        return dateStr ;
    }
    
    // Transforme la valeur Java en XML
    @Override
    public String toString(Object obj) {
        final Date date = (Date)obj;
        
        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd") ;
        
        return sdf.format(date) ;
    }
}

vendredi 17 mai 2013

Tutoriel MyBatis

Vous cherchez une alternative à Hibernate ?
Vous souhaitez utiliser un ORM plus simple à mettre en oeuvre ?

Alors essayez MyBatis et pour ce faire, vous trouverez sur ce blog un tutoriel complet (voir les liens à côté).

lundi 13 mai 2013

Changer la convention des noms des balises avec XStream (exemple avec les underscores)

Afin de ne pas avoir de double underscore ("_"), il est nécessaire d'indiquer à XStream la convention de nommage des balises.
Cela ce fait à la création de l'objet XStream :
XStream stream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));

lundi 6 mai 2013

Changer le nom des balises XML avec XStream (utilisation des alias)

Il est possible via des annotations de changer le nom de la balise dans le flux XML.
En reprenant la classe Toto :
import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("produit")
public class Toto {
  @XStreamAlias("id")
  public String toto = "1";
  
  @XStreamAlias("liste_Produit")
  public List titi = new ArrayList() ;
  
  @XStreamAlias("date_Envoie")
  public Date tata = new Date() ;

Il est nécessaire d'indiquer à XStream de prendre en compte les annotations, en ajoutant, avant de générer le rendu, la ligne suivante :
stream.autodetectAnnotations(true) ;

Voici le nouveau rendu :
<produit>
  <id>1</id>
  <liste__Produit>
    <string>truc</string>
    <string>bidule</string>
  </liste__Produit>
  <date__Envoie>2013-02-28 17:01:29.669 UTC</date__Envoie>
</produit>
Vous remarquerez peut-être que les alias avec un underscore ("_"), voit celui-ci doublé.
La raison est expliquer dans la FAQ de XStream.