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 adresseAdresseType: 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.xsd4. 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 postaleObjectFactory.java: Factory permettant de créer des instances des classes généréespackage-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 personnalisationZipCodeType2: Type simple restreint sans personnalisationpersoninfo: Type complexe contenant firstname et lastnamefullpersoninfo: Type complexe étendant personinfo avec address, city, country, zip, zip2
b. Mapping des types XML vers Java :
xsd:string→Stringxsd: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 mylastnameFullpersoninfo.java: Classe étendue avec address, city, country, zip, zip2ObjectFactory.java: Factory pour créer les instancespackage-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: SalaireString bio: BiographieZonedDateTime joinDate: Date d’embauche avec fuseau horaire
Propriétés de Entreprise.java :
List<Employe> list: Liste des employésString 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@XmlAttributesurid: Transformeiden attribut XML@XmlJavaTypeAdapter(TimeZoneAdaptor.class)surjoinDate: 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→Stringau 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 unZonedDateTimeenStringformatéeunmarshal(String v): Parse uneStringpour créer unZonedDateTime
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>