Partie 1 : Préparation de l’environnement

Installation classique

Partie 2 : Génération de classes Java à partir d’un schéma XML

1-2. Exploration du fichier employes.xsd

Le schéma définit deux types de données principaux :

  • employeType : Type complexe décrivant un employé avec les éléments nss, nom, prénom et adresse
  • AdresseType : Type complexe décrivant une adresse avec Num, Rue, Ville et CodeP

3. Génération des classes Java

xjc.sh -p tpjaxb -d tpjaxb-generated employes.xsd

4. Classes générées et leurs rôles

Les classes suivantes sont créées :

  • EmployeType.java : Représente un employé avec ses propriétés (nss, nom, prénom, adresse)
  • AdresseType.java : Représente une adresse postale
  • ObjectFactory.java : Factory permettant de créer des instances des classes générées
  • package-info.java : Contient les métadonnées du package (namespace, annotations)

5. Analyse des options de binding par défaut

Par défaut, JAXB convertit les types complexes XML en classes Java et transforme les éléments XML en propriétés Java avec getters/setters

6. Personnalisation des bindings

<xsd:complexType name="employeType">
  <xsd:annotation>
    <xsd:appinfo>
      <jxb:class name="MesEmployes">
        <jxb:javadoc>Classe générée par des mappings personnalisés</jxb:javadoc>
      </jxb:class>
    </xsd:appinfo>
  </xsd:annotation>
  <xsd:sequence>
  </xsd:sequence>
</xsd:complexType>

7. Création et sérialisation d’une instance

Programme MyMarshaller.java :

package tpjaxb;
 
import jakarta.xml.bind.*;
import java.io.*;
 
public class MyMarshaller {
    public static void main(String[] args) {
        try {
            JAXBContext context = JAXBContext.newInstance(EmployeType.class);
            ObjectFactory factory = new ObjectFactory();
            EmployeType employe = factory.createEmployeType();
            employe.setNss("0000001");
            employe.setNom("Martin");
            employe.setPrenom("Paul");
            AdresseType adresse = factory.createAdresseType();
            adresse.setNum(10);
            adresse.setRue("Avenue de la Libération");
            adresse.setVille("Clermont-Ferrand");
            adresse.setCodeP(63000);
            employe.setAdresse(adresse);
            
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(employe, System.out);
            
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

Résultat affiché :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employeType>
    <nss>0000001</nss>
    <nom>Martin</nom>
    <prenom>Paul</prenom>
    <adresse>
        <Num>10</Num>
        <Rue>Avenue de la Libération</Rue>
        <Ville>Clermont-Ferrand</Ville>
        <CodeP>63000</CodeP>
    </adresse>
</employeType>

8. Sérialisation dans un fichier XML

Modification du programme pour écrire dans mesemployes.xml :

marshaller.marshal(employe, new File("mesemployes.xml"));

Le fichier mesemployes.xml est créé avec le contenu XML de l’employé.

9. Unmarshalling : Désérialisation depuis XML

Programme MyUnmarshaller.java :

package tpjaxb;
 
import jakarta.xml.bind.*;
import java.io.*;
 
public class MyUnmarshaller {
    public static void main(String[] args) {
        try {
            JAXBContext context = JAXBContext.newInstance(EmployeType.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            File xmlFile = new File("mesemployes2.xml");
            EmployeType employe = (EmployeType) unmarshaller.unmarshal(xmlFile);
            System.out.println("NSS: " + employe.getNss());
            System.out.println("Nom: " + employe.getNom());
            System.out.println("Prénom: " + employe.getPrenom());
            System.out.println("Ville: " + employe.getAdresse().getVille());
            
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

Résultat :

NSS: 0000001
Nom: Martin
Prénom: Paul
Ville: Clermont-Ferrand

10-11. Analyse du schéma myTest.xsd

a. Types de données définis :

  • ZipCodeType : Type simple restreint (entier entre 10000 et 99999) avec personnalisation
  • ZipCodeType2 : Type simple restreint sans personnalisation
  • personinfo : Type complexe contenant firstname et lastname
  • fullpersoninfo : Type complexe étendant personinfo avec address, city, country, zip, zip2

b. Mapping des types XML vers Java :

  • xsd:string String
  • xsd:integer (ZipCodeType) int (via personnalisation)
  • xsd:integer (ZipCodeType2) BigInteger (mapping par défaut)
  • Types complexes Classes Java corespondantes

c. Personnalisation de l’élément firstname :

<jxb:property name="myfirstname" generateIsSetMethod="true"/>

d. Personnalisation de l’élément lastname :

<jxb:property name="mylastname" generateIsSetMethod="false"/>

e. Personnalisation de ZipCodeType :

<jxb:javaType name="int" 
    parseMethod="mypackage.MyDatatypeConverter.parseIntegerToInt" 
    printMethod="mypackage.MyDatatypeConverter.printIntToInteger" />

12. Compilation du schéma myTest.xsd

Classes générées :

  • Personinfo.java : Classe de base avec les propriétées myfirstname et mylastname
  • Fullpersoninfo.java : Classe étendue avec address, city, country, zip, zip2
  • ObjectFactory.java : Factory pour créer les instances
  • package-info.java : Métadonnées du package

Les personnalisations sont appliquées : les propriétées portent bien les noms myfirstname et mylastname, et ZipCodeType est mappé en int.

13. Ajout de personnalisation pour ZipCodeType2

a. Signification de l’annotation :

L’annotation indique que ZipCodeType2 doit être mappé vers le type primitif int en Java au lieu du type BigInteger par défaut.

b. Nouvelles classes générées :

Après recompilation, la classe Fullpersoninfo.java est modifiée. La propriété zip2 est maintenant de type int au lieu de BigInteger, ce qui optimise l’espace mémoire.

Partie 3 : Génération de schéma XML à partir de classes Java

3. Annotation

a. Signification de @XmlRootElement :

Cette annotation indique que la classe Customer correspond à un élément racine dans le document XML. Elle permet à JAXB de marshaller/unmarshaller directement des instances de cette classe.

b. Mapping de l’attribut Name :

L’attribut name est mappé comme un élément XML <name> car JAXB accède aux propriétés via les getters/setters par défaut.

c. Mapping de l’attribut Rank :

Même procédé de mapping mais son getter et setter est customisé.

d. Mapping de l’attribut Hobbies :

L’attribut hobbies n’apparaît pas dans le schéma généré car il n’a pas de getter/setter public défini dans la classe.

4. Annotation 2

a. Signification de @XmlAccessorType(XmlAccessType.FIELD) :

Cette annotation indique à JAXB d’accéder directement aux champs (fields) de la classe, qu’ils soient publics ou privés, sans passer par les getters/setters.

b. Mapping de Hobbies :

L’attribut hobbies apparaît maintenant dans le schéma comme un élément <hobbies> de type collection. JAXB accède directement au champ privé List<String> hobbies afin de capturer tous les attributs de la classe, même ceux sans getters/setters.

5. Annotation 3

a. Signification de @XmlAccessorType(XmlAccessType.PROPERTY) :

Cette annotation force JAXB à utiliser uniquement les getters/setters pour accéder aux propriétés, en ignorant les champs qui n’ont pas de méthodes d’accès.

b. Mapping de Hobbies :

L’attribut hobbies disparaît du schéma car aucun getter/setter n’est défini pour cette propriété dans la classe Customer.

6. Annotation 4

a. Résultat :

Lors de la génération du schéma, l’élément id n’apparaît plus dans le schéma XML, que l’accès soit par champ ou par propriété.

b. Signification de @XmlTransient :

Cette annotation indique à JAXB d’ignorer complètement ce champ lors du marshalling/unmarshalling. Le champ id ne sera ni sérialisé ni désérialisé.

7. Retour à @XmlAccessorType(XmlAccessType.FIELD)

a. Résultat :

L’élément id reste exclu du schéma XML car @XmlTransient prend le dessus sur le mode d’accès. Tous les autres champs (name, age, rank, hobbies) apparaissent dans le schéma.

8. Personnalisation des mappings

a. Renommer id en MyId :

@XmlElement(name = "MyId")
int id;

Résultat : Dans le schéma XML, l’élément est maintenant nommé <MyId> au lieu de <id>.

b. Transformer name en attribut XML :

@XmlAttribute
String name;

Résultat : Dans le schéma XML, name est défini comme un attribut (<xsd:attribute name="name" type="xsd:string"/>) au lieu d’un élément.

9. Ordonnancement des éléments XML

Ajout de l’annotation @XmlType :

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {"id", "age", "name", "hobbies", "rank"})
public class Customer {
    // ...
}

Résultat : Le schéma XML généré définit l’ordre des éléments selon la séquence spécifiée. Les documents XML produits respecteront cet ordre lors du marshalling.

Partie 4 : Personnalisation des types de données avec adaptateur

1-2. Analyse des classes du package model

Fichiers récupérés : Employe.java et Entreprise.java

Propriétés de Employe.java :

  • int id : Identifiant de l’employé
  • String name : Nom de l’employé
  • String Salary : Salaire
  • String bio : Biographie
  • ZonedDateTime joinDate : Date d’embauche avec fuseau horaire

Propriétés de Entreprise.java :

  • List<Employe> list : Liste des employés
  • String name : Nom de l’entreprise

3. Signification des annotations

Dans Employe.java :

  • @XmlRootElement : Définit la classe comme élément racine XML
  • @XmlAccessorType(XmlAccessType.FIELD) : Accès direct aux champs
  • @XmlAttribute sur id : Transforme id en attribut XML
  • @XmlJavaTypeAdapter(TimeZoneAdaptor.class) sur joinDate : Utilise un adaptateur personnalisé pour la conversion

Dans Entreprise.java :

  • @XmlRootElement : Élément racine
  • @XmlType(propOrder = {"name", "list"}) : Définit l’ordre des éléments
  • @XmlAccessorType(XmlAccessType.FIELD) : Accès par champ
  • @XmlElement(name = "employes") : Renomme la liste en <employes> dans le XML

4. Type de la propriété joinDate

La propriété joinDate est de type ZonedDateTime, qui représente une date-heure avec fuseau horaire (de l’API Java 8+ java.time).

5. Traduction XML de joinDate

Sans adaptateur, JAXB ne sait pas comment marshaller/unmarshaller un ZonedDateTime. L’adaptateur TimeZoneAdaptor convertit :

  • Marshalling : ZonedDateTime String au format ISO_OFFSET_DATE_TIME
  • Unmarshalling : String ZonedDateTime

Exemple de résultat XML :

<joinDate>2021-12-10T08:30:00+01:00</joinDate>

6. Rôle de TimeZoneAdaptor.java

La classe TimeZoneAdaptor étend XmlAdapter<String, ZonedDateTime> et définit :

  • marshal(ZonedDateTime v) : Convertit un ZonedDateTime en String formatée
  • unmarshal(String v) : Parse une String pour créer un ZonedDateTime

Elle utilise DateTimeFormatter.ISO_OFFSET_DATE_TIME pour garantir un format standardisé incluant le fuseau horaire.

7. Programme Transfert.java

Programme pour exporter des instances vers XML :

package tpexo3;
 
import jakarta.xml.bind.*;
import tpexo3.model.*;
import java.io.*;
import java.time.ZonedDateTime;
import java.util.*;
 
public class Transfert {
    public static void main(String[] args) {
        try {
            Employe emp1 = new Employe();
            emp1.setId(1);
            emp1.setName("Alice Martin");
            emp1.setSalary("45000");
            emp1.setBio("Développeuse senior spécialisée en Java");
            emp1.setJoinDate(ZonedDateTime.now());
            
            Employe emp2 = new Employe();
            emp2.setId(2);
            emp2.setName("Bob Durand");
            emp2.setSalary("38000");
            emp2.setBio("Analyste fonctionnel");
            emp2.setJoinDate(ZonedDateTime.now().minusYears(2));
            
            Entreprise entreprise = new Entreprise();
            entreprise.setName("TechCorp Solutions");
            List<Employe> employes = new ArrayList<>();
            employes.add(emp1);
            employes.add(emp2);
            entreprise.setList(employes);
            
            JAXBContext context = JAXBContext.newInstance(Entreprise.class);
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            
            marshaller.marshal(entreprise, new File("entreprise.xml"));
            marshaller.marshal(entreprise, System.out);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

8. Test du programme :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<entreprise>
    <name>TechCorp Solutions</name>
    <employes id="1">
        <name>Alice Martin</name>
        <Salary>45000</Salary>
        <bio>Développeuse senior spécialisée en Java</bio>
        <joinDate>2025-12-10T14:30:00+01:00</joinDate>
    </employes>
    <employes id="2">
        <name>Bob Durand</name>
        <Salary>38000</Salary>
        <bio>Analyste fonctionnel</bio>
        <joinDate>2023-12-10T14:30:00+01:00</joinDate>
    </employes>
</entreprise>