Guide de l’utilisateur XStream: Conversion d’objets en XML

XStream User Guide: Conversion d'objets en XML

1. Vue d'ensemble

Dans ce didacticiel, nous allons apprendre à utiliser la bibliothèqueXStream pour sérialiser des objets Java en XML.

2. Caractéristiques

L'utilisation de XStream pour la sérialisation et la désérialisation de XML présente de nombreux avantages intéressants:

  • Configuré correctement, il produit trèsclean XML

  • Fournit des opportunités significatives pourcustomization de la sortie XML

  • Prise en charge deobject graphs, y compris les références circulaires

  • Dans la plupart des cas d'utilisation, l'instance XStream estthread-safe, once configured (il y a des mises en garde lors de l'utilisation d'annotations)

  • Des messages clairs sont fournis pendantexception handling pour aider à diagnostiquer les problèmes

  • À partir de la version 1.4.7, nous avonssecurity features disponibles pour interdire la sérialisation de certains types

3. Configuration du projet

Pour utiliser XStream dans notre projet, nous allons ajouter la dépendance Maven suivante:


    com.thoughtworks.xstream
    xstream
    1.4.9

4. Utilisation de base

La classeXStream est une façade pour l'API. Lors de la création d'une instance deXStream, nous devons également prendre en charge les problèmes de sécurité des threads:

XStream xstream = new XStream();

Une fois qu'une instance est créée et configurée, elle peut être partagée entre plusieurs threads pour le marshalling / unmarshalling sauf si vous activez le traitement des annotations.

4.1. Conducteurs

Plusieurs pilotes sont pris en charge, tels queDomDriver,StaxDriver,XppDriver, etc. Ces pilotes ont des performances et des caractéristiques d’utilisation des ressources différentes.

Le pilote XPP3 est utilisé par défaut, mais nous pouvons bien sûr changer de pilote facilement:

XStream xstream = new XStream(new StaxDriver());

4.2. Générer du XML

Commençons par définir un POJO simple pour -Customer:

public class Customer {

    private String firstName;
    private String lastName;
    private Date dob;

    // standard constructor, setters, and getters
}

Générons maintenant une représentation XML de l'objet:

Customer customer = new Customer("John", "Doe", new Date());
String dataXml = xstream.toXML(customer);

En utilisant les paramètres par défaut, la sortie suivante est générée:


    John
    Doe
    1986-02-14 03:46:16.381 UTC

À partir de cette sortie, nous pouvons clairement voir que la balise contenant utilise le nom de classe complet deCustomer par défaut.

Il existe de nombreuses raisons pour lesquelles nous pouvons décider que le comportement par défaut ne répond pas à nos besoins. Par exemple, nous ne serions peut-être pas à l'aise d'exposer la structure de package de notre application. En outre, le XML généré est considérablement plus long.

5. Alias

Unalias est un nom que nous souhaitons utiliser pour les éléments plutôt que d'utiliser des noms par défaut.

Par exemple, nous pouvons remplacercom.example.pojo.Customer parcustomer en enregistrant un alias pour la classeCustomer. Nous pouvons également ajouter des alias pour les propriétés d'une classe. En utilisant des alias, nous pouvons rendre notre sortie XML beaucoup plus lisible et moins spécifique à Java.

5.1. Alias ​​de classe

Les alias peuvent être enregistrés par programme ou à l'aide d'annotations.

Annotons maintenant notre classeCustomer avec@XStreamAlias:

@XStreamAlias("customer")

Nous devons maintenant configurer notre instance pour utiliser cette annotation:

xstream.processAnnotations(Customer.class);

Alternativement, si nous souhaitons configurer un alias par programme, nous pouvons utiliser le code ci-dessous:

xstream.alias("customer", Customer.class);

Que vous utilisiez l'alias ou la configuration programmatique, la sortie d'un objetCustomer sera beaucoup plus propre:


    John
    Doe
    1986-02-14 03:46:16.381 UTC

5.2. Alias ​​de champ

Nous pouvons également ajouter des alias pour les champs en utilisant la même annotation que celle utilisée pour les classes d'alias. Par exemple, si nous voulions que le champfirstName soit remplacé parfn dans la représentation XML, nous pourrions utiliser l'annotation suivante:

@XStreamAlias("fn")
private String firstName;

Alternativement, nous pouvons atteindre le même objectif par programme:

xstream.aliasField("fn", Customer.class, "firstName");

La méthodealiasField accepte trois arguments: l'alias que nous souhaitons utiliser, la classe dans laquelle la propriété est définie et le nom de la propriété que nous souhaitons aliaser.

Quelle que soit la méthode utilisée, le résultat est le même:


    John
    Doe
    1986-02-14 03:46:16.381 UTC

5.3. Alias ​​par défaut

Il existe plusieurs alias pré-enregistrés pour les cours. En voici quelques-uns:

alias("float", Float.class);
alias("date", Date.class);
alias("gregorian-calendar", Calendar.class);
alias("url", URL.class);
alias("list", List.class);
alias("locale", Locale.class);
alias("currency", Currency.class);

6. Des collections

Nous allons maintenant ajouter une liste deContactDetails à l'intérieur de la classeCustomer.

private List contactDetailsList;

Avec les paramètres par défaut pour la gestion des collections, voici le résultat:


    John
    Doe
    1986-02-14 04:14:05.874 UTC
    
        
            6673543265
            0124-2460311
        
        
            4676543565
            0120-223312
        
    

Supposons que nous devions omettre les balises parentcontactDetailsList, et que nous voulions juste que chaque élémentContactDetails soit un enfant de l'élémentcustomer. Modifions encore notre exemple:

xstream.addImplicitCollection(Customer.class, "contactDetailsList");

Désormais, lorsque le XML est généré, les balises racine sont omises, ce qui donne le XML ci-dessous:


    John
    Doe
    1986-02-14 04:14:20.541 UTC
    
        6673543265
        0124-2460311
    
    
        4676543565
        0120-223312
    

La même chose peut également être obtenue en utilisant des annotations:

@XStreamImplicit
private List contactDetailsList;

7. Convertisseurs

XStream utilise une carte d'instancesConverter, chacune avec sa propre stratégie de conversion. Celles-ci convertissent les données fournies dans un format particulier en XML et inversement.

En plus d'utiliser les convertisseurs par défaut, nous pouvons modifier les valeurs par défaut ou enregistrer des convertisseurs personnalisés.

7.1. Modification d'un convertisseur existant

Supposons que nous ne soyons pas satisfaits de la façon dont les balisesdob ont été générées_ using the default settings. We can modify the custom converter for _Date fournies par XStream (DateConverter):

xstream.registerConverter(new DateConverter("dd-MM-yyyy", null));

Ce qui précède produira la sortie au format «dd-MM-yyyy»:


    John
    Doe
    14-02-1986

7.2. Convertisseurs personnalisés

Nous pouvons également créer un convertisseur personnalisé pour obtenir le même résultat que dans la section précédente:

public class MyDateConverter implements Converter {

    private SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");

    @Override
    public boolean canConvert(Class clazz) {
        return Date.class.isAssignableFrom(clazz);
    }

    @Override
    public void marshal(
      Object value, HierarchicalStreamWriter writer, MarshallingContext arg2) {
        Date date = (Date)value;
        writer.setValue(formatter.format(date));
    }

    // other methods
}

Enfin, nous enregistrons notre classeMyDateConverter comme ci-dessous:

xstream.registerConverter(new MyDateConverter());

Nous pouvons également créer des convertisseurs qui implémentent l'interfaceSingleValueConverter, qui est conçue pour convertir un objet en chaîne.

public class MySingleValueConverter implements SingleValueConverter {

    @Override
    public boolean canConvert(Class clazz) {
        return Customer.class.isAssignableFrom(clazz);
    }

    @Override
    public String toString(Object obj) {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
        Date date = ((Customer) obj).getDob();
        return ((Customer) obj).getFirstName() + ","
          + ((Customer) obj).getLastName() + ","
          + formatter.format(date);
    }

    // other methods
}

Enfin, nous enregistronsMySingleValueConverter:

xstream.registerConverter(new MySingleValueConverter());

En utilisantMySingleValueConverter, la sortie XML pour unCustomer est la suivante:

John,Doe,14-02-1986

7.3. Priorité du convertisseur

Lors de l'enregistrement des objetsConverter, il est également possible de définir leur niveau de priorité.

À partir desXStream javadocs:

Les convertisseurs peuvent être enregistrés avec une priorité explicite. Par défaut, ils sont enregistrés auprès de XStream.PRIORITY_NORMAL. Les convertisseurs de même priorité seront utilisés dans l'ordre inverse de leur enregistrement. Le convertisseur par défaut, c'est-à-dire le convertisseur qui sera utilisé si aucun autre convertisseur enregistré ne convient, peut être enregistré avec la priorité XStream.PRIORITY_VERY_LOW. XStream utilise par défaut ReflectionConverter comme convertisseur de secours.

L'API fournit plusieurs valeurs de priorité nommées: **

private static final int PRIORITY_NORMAL = 0;
private static final int PRIORITY_LOW = -10;
private static final int PRIORITY_VERY_LOW = -20;

8. Omettre des champs

Nous pouvons omettre les champs de notre XML généré en utilisant des annotations ou une configuration par programme. Afin d'omettre un champ utilisant une annotation, nous appliquons simplement l'annotation@XStreamOmitField au champ en question:

@XStreamOmitField
private String firstName;

Pour omettre le champ par programme, nous utilisons la méthode suivante:

xstream.omitField(Customer.class, "firstName");

Quelle que soit la méthode choisie, le résultat est le même:


    Doe
    14-02-1986

9. Champs d'attribut

Parfois, nous pouvons souhaiter sérialiser un champ en tant qu'attribut d'un élément plutôt qu'en tant qu'élément lui-même. Supposons que nous ajoutions un champcontactType:

private String contactType;

Si nous voulons définircontactType comme attribut XML, nous pouvons utiliser l'annotation@XStreamAsAttribute:

@XStreamAsAttribute
private String contactType;

Alternativement, nous pouvons atteindre le même objectif par programme:

xstream.useAttributeFor(ContactDetails.class, "contactType");

Le résultat de l'une des méthodes ci-dessus est le même:


    6673543265
    0124-2460311

10. Simultanéité

Le modèle de traitement de XStream présente certains défis. Une fois que l'instance est configurée, elle est thread-safe.

Il est important de noter que le traitement des annotations modifie la configuration juste avant le marshalling / unmarshalling. Et donc - si nous exigeons que l'instance soit configurée à la volée à l'aide d'annotations, il est généralement judicieux d'utiliser une instanceXStream distincte pour chaque thread.

11. Conclusion

Dans cet article, nous avons abordé les bases de l’utilisation de XStream pour convertir des objets en XML. Nous avons également appris les personnalisations que nous pouvons utiliser pour nous assurer que la sortie XML répond à nos besoins. Enfin, nous avons examiné les problèmes de sécurité des threads avec des annotations.

Dans le prochain article de cette série, nous étudierons la conversion de XML en objets Java.

Le code source complet de cet article peut être téléchargé à partir desGitHub repository liés.