web-dev-qa-db-fra.com

JAXB: Comment marshaler des objets dans des listes?

Peut-être une question stupide: j'ai un List de type <Data> que je veux rassembler dans un fichier XML. Ceci est ma classe Database contenant un ArrayList...

@XmlRootElement
public class Database
{
    List<Data> records = new ArrayList<Data>();

    public List<Data> getRecords()                   { return records; }
    public void       setRecords(List<Data> records) { this.records = records; }
}

... et voici les données de la classe:

// @XmlRootElement
public class Data 
{
    String name;
    String address;

    public String getName()            { return name;      }
    public void   setName(String name) { this.name = name; }

    public String getAddress()               { return address;         }
    public void   setAddress(String address) { this.address = address; }
}

Utilisation de la classe de test suivante ...

public class Test
{
    public static void main(String args[]) throws Exception
    {
        Data data1 = new Data();
             data1.setName("Peter");
             data1.setAddress("Cologne");

        Data data2 = new Data();
             data2.setName("Mary");
             data2.setAddress("Hamburg");

        Database database = new Database();
                 database.getRecords().add(data1);
                 database.getRecords().add(data2);

        JAXBContext context = JAXBContext.newInstance(Database.class);
        Marshaller marshaller = context.createMarshaller();
                   marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                   marshaller.marshal(database, new FileWriter("test.xml"));       
    }
}

... j'ai obtenu le résultat:

<database>
    <records>
        <address>Cologne</address>
        <name>Peter</name>
    </records>
    <records>
        <address>Hamburg</address>
        <name>Mary</name>
    </records>
</database>

Mais ce n'est pas ce que j'attendais, c'est-à-dire toutes les balises pour <Data> il manque des objets. Je cherche un moyen d'exporter les données dans la structure suivante, mais je ne sais pas comment y parvenir:

<database>
    <records>
        <data>
            <address>Cologne</address>
            <name>Peter</name>
        </data>
        <data>
            <address>Hamburg</address>
            <name>Mary</name>
        </data>
    </records>
</database>

Une question supplémentaire: si je veux résoudre le problème sans en utilisant @XmlElementWrapper et @XmlElement annotations, je peux introduire une classe intermédiaire

public class Records
{
    List<Data> data = new ArrayList<Data>();

    public List<Data> getData()                { return data; }
    public void       setData(List<Data> data) { this.data = data; }
}

utilisé par la classe de base modifiée

@XmlRootElement
public class Database
{
    Records records = new Records();

    public Records getRecords()                { return records; }
    public void    setRecords(Records records) { this.records = records; }
}

dans une classe Test légèrement modifiée:

...
Database database = new Database();
database.getRecords().getData().add(data1);
database.getRecords().getData().add(data2);
...

Le résultat est également:

<database>
    <records>
        <data>
            <address>Cologne</address>
            <name>Peter</name>
        </data>
        <data>
            <address>Hamburg</address>
            <name>Mary</name>
        </data>
    </records>
</database>

Est-ce la manière recommandée de créer une structure de classe Java selon la structure de fichier XML ci-dessus?

60
rmv

Dans la propriété records, ajoutez:

@XmlElementWrapper(name="records")
@XmlElement(name="data")

Pour plus d'informations sur JAXB et les propriétés de collection, voir:

97
bdoughan

Ceci est en réponse à votre deuxième question a demandé une réponse:

Les deux approches généreront le même XML. Ma recommandation est d'aller avec le modèle qui convient le mieux à votre application. Pour moi, cela utilise généralement @ XmlElementWrapper/@ XmlElement. Puisque "records" est juste là pour organiser les éléments "data", il ne mérite pas vraiment sa propre classe.

Je dirige l'implémentation MOXy JAXB et nous proposons une extension de mappage basée sur XPath pour aller au-delà de ce qui est capable avec @XmlElementWrapper:

5
bdoughan

En réponse à votre deuxième question:

Is this the recommended way to create a Java class structure
according to the XML file structure above?

Techniquement parlant, l'introduction d'une classe Records supplémentaire pour résoudre votre problème JAXB est un travail inutile et redondant, car JAXB n'en a pas besoin. Le @XmlElementWrapper et @XmlElementname La propriété a été conçue pour résoudre votre problème.

De vos commentaires à la réponse de Blaise, je maintiens un tutoriel avec des exemples opérationnels expliquant comment faire face aux classes génériques telles que List, etc. lors du démarshalling.

4