|
|
|
|
|
|
Développons en Java v 1.60 | |
| Copyright (C) 1999-2011 Jean-Michel DOUDOUX |
![]() |
![]() |
![]() |
JAXB est une spécification qui permet de faire correspondre un document XML à un ensemble de classes et vice et versa via des opérations de sérialisation/désérialisation nommée marshaling/unmarshaling.
JAXB permet aux développeurs de manipuler un document XML sans avoir à connaître XML ou la façon dont un document XML est traitée comme cela est le cas avec SAX, DOM ou StAX. La manipulation du document XML se fait en utilisant des objets précédemment générés à partir d'une DTD pour JAXB 1.0 et d'un schéma XML du document à traiter pour JAXB 2.0.
Le page officiel de JAXB est à l'url : Java Architecture for XML Binding (JAXB)
Ce chapitre contient plusieurs sections :
JAXB est l'acronyme de Java Architecture for XML Binding.
Le but de l'API et des spécifications JAXB est de faciliter la manipulation d'un document XML en générant un ensemble de classes qui fournissent un niveau d'abstraction plus élevé que l'utilisation de JAXP (SAX ou DOM). Avec ces deux API, toute la logique de traitements des données contenues dans le document est à écrire.
JAXB au contraire fournit un outil qui analyse un schéma XML et génère à partir de ce dernier un ensemble de classes qui vont encapsuler les traitements de manipulation du document.
Le grand avantage est de fournir au développeur un moyen de manipuler un document XML sans connaître XML ou les technologies d'analyse. Toutes les manipulations se font au travers d'objets java.
Ces classes sont utilisées pour faire correspondre le document XML dans des instances de ces classes et vice et versa : ces opérations se nomment respectivement unmarshalling et marshalling.
L'implémentation de référence de JAXB v1.0 est fournie avec le JSWDK 1.1.
Les exemples de ce chapitre utilisent cette implémentation de référence et le fichier XML suivant :
| Exemple : |
<bibliotheque>
<livre>
<titre>titre 1</titre>
<auteur>auteur 1</auteur>
<editeur>editeur 1</editeur>
</livre>
<livre>
<titre>titre 2</titre>
<auteur>auteur 2</auteur>
<editeur>editeur 2</editeur>
</livre>
<livre>
<titre>titre 3</titre>
<auteur>auteur 3</auteur>
<editeur>editeur 3</editeur>
</livre>
</bibliotheque> |
Le schéma XML correspondant à ce fichier XML est le suivant :
| Exemple : |
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="bibliotheque">
<xs:complexType>
<xs:sequence>
<xs:element ref="livre" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="livre">
<xs:complexType>
<xs:sequence>
<xs:element ref="titre"/>
<xs:element ref="auteur"/>
<xs:element ref="editeur"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="titre" type="xs:string"/>
<xs:element name="auteur" type="xs:string"/>
<xs:element name="editeur" type="xs:string"/>
</xs:schema> |
L'outil xjc permet d'analyser un schéma XML et de générer les interfaces et les classes qui vont permettre la manipulation d'un document XML qui respecte ce schéma. Cette opération se nomme binding.
La syntaxe de cet outil est très simple :
xjc [options] schema
schema est le nom d'un fichier contenant le schéma XML.
Les principales options sont les suivantes :
| Exemple : |
C:\java\jaxb>xjc test.xsd parsing a schema... compiling a schema... generated\impl\AuteurImpl.java generated\impl\BibliothequeImpl.java generated\impl\BibliothequeTypeImpl.java generated\impl\EditeurImpl.java generated\impl\LivreImpl.java generated\impl\LivreTypeImpl.java generated\impl\TitreImpl.java generated\Auteur.java generated\Bibliotheque.java generated\BibliothequeType.java generated\Editeur.java generated\Livre.java generated\LivreType.java generated\ObjectFactory.java generated\Titre.java generated\bgm.ser generated\jaxb.properties |
L'exécution de la commande de l'exemple génère les fichiers suivants :
| Generated | ||
| Auteur.java bgm.ser Bibliotheque.java BibliothequeType.java Editeur.java jaxb.properties Livre.java LivreType.java ObjectFactory.java Titre.java generated\impl |
||
| AuteurImpl.java | ||
| BibliothequeImpl.java | ||
| BibliothequeTypeImpl.java | ||
| EditeurImpl.java | ||
| LivreImpl.java | ||
| LivreTypeImpl.java | ||
| TitreImpl.java | ||
Sans précision, les fichiers générés le sont dans le répertoire "Generated".
Pour préciser un autre répertoire, il faut utiliser l'option -d :
xjc -d sources test.xsd
Les classes et interfaces sont générées dans le répertoire "sources/generated"
Si le répertoire précisé n'existe pas, une exception est levée.
| Exemple : |
C:\java\jaxb>xjc -d sources test.xsd
parsing a schema...
compiling a schema...
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39) |
Pour éviter l'utilisation du répertoire "generated", il faut préciser un package pour les entités générées en utilisant l'option -p.
| Exemple : |
C:\java\jaxb>xjc -d sources -p com.jmdoudoux.test.jaxb test.xsd parsing a schema... compiling a schema... com\moi\test\jaxb\Auteur.java com\moi\test\jaxb\Bibliotheque.java com\moi\test\jaxb\BibliothequeType.java com\moi\test\jaxb\Editeur.java com\moi\test\jaxb\Livre.java com\moi\test\jaxb\LivreType.java com\moi\test\jaxb\ObjectFactory.java com\moi\test\jaxb\Titre.java com\moi\test\jaxb\jaxb.properties com\moi\test\jaxb\bgm.ser com\moi\test\jaxb\impl\AuteurImpl.java com\moi\test\jaxb\impl\BibliothequeImpl.java com\moi\test\jaxb\impl\BibliothequeTypeImpl.java com\moi\test\jaxb\impl\EditeurImpl.java com\moi\test\jaxb\impl\LivreImpl.java com\moi\test\jaxb\impl\LivreTypeImpl.java com\moi\test\jaxb\impl\TitreImpl.java |
Un objet de type factory et des interfaces pour chacun des éléments qui compose le document sont définis.
Pour chaque élément qui peut contenir d'autres éléments, des interfaces de XXXType sont créées (BibliothequeType et LivreType dans l'exemple).
L'interface BibliothequeType définit simplement un getter sur une collection qui contiendra tous les livres.
L'interface LivreType définit des getters et des setters sur les éléments auteur, editeur et titre.
Les interfaces Titre, Editeur et Auteur définissent un getter et un setter sur la valeur des données que ces éléments contiennent.
La classe ObjectFactory permet de créer des instances des différentes entités définies.
Le répertoire impl contient les classes qui implémentent ces interfaces. Ces classes sont spécifiques à l'implémentation des spécifications JAXB utilisées.
Pour pouvoir utiliser ces interfaces et ces classes, il faut les compiler en incluant tous les fichiers .jar contenus dans le répertoire lib de l'implémentation de JAXB au classpath.
L'API JAXB propose un framework composé de classes regroupées dans trois packages :
Pour pouvoir utiliser JAXP, il faut tout d'abord obtenir un objet de type JAXBContext qui est le point d'entrée pour utiliser l'API. Il faut utiliser la méthode newInstance() qui attend en paramètre le nom du package qui contient les interfaces générées (celui fournit au paramètre -p de la commande xjc).
Pour pouvoir créer en mémoire les objets qui représentent le document XML, il faut à partir de l'instance du type JAXBContext, appeler la méthode createUnmarshaller() qui renvoie un objet de type Unmarshaller.
L'appel de la méthode unmarshal() permet de créer les différents objets.
Pour parcourir le document, il suffit d'utiliser les différents objets instanciés.
| Exemple : |
package com.jmdoudoux.test.jaxb;
import javax.xml.bind.*;
import java.io.*;
import java.util.*;
public class TestJAXB {
public static void main(String[] args) {
try {
JAXBContext jc = JAXBContext.newInstance("com.jmdoudoux.test.jaxb");
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setValidating(true);
Bibliotheque bibliotheque = (Bibliotheque) unmarshaller.unmarshal(new File("test.xml"));
List livres = bibliotheque.getLivre();
for (int i = 0; i < livres.size(); i++) {
LivreType livre = (LivreType) livres.get(i);
System.out.println("Livre ");
System.out.println("Titre : " + livre.getTitre());
System.out.println("Auteur : " + livre.getAuteur());
System.out.println("Editeur : " + livre.getEditeur());
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
}
} |
| Résultat : |
Livre Titre : titre 1 Auteur : auteur 1 Editeur : editeur 1 Livre Titre : titre 2 Auteur : auteur 2 Editeur : editeur 2 Livre Titre : titre 3 Auteur : auteur 3 Editeur : editeur 3 |
Parmi les classes générées à partir du schéma XML, il y a la classe ObjectFactory qui permet de créer des instances des autres classes générées.
| Exemple : |
import javax.xml.bind.*;
import java.io.*;
import java.util.*;
public class TestJAXB2 {
public static void main(String[] args) {
try {
ObjectFactory objFactory = new ObjectFactory();
Bibliotheque bibliotheque = (Bibliotheque) objFactory.createBibliotheque();
List livres = bibliotheque.getLivre();
for (int i = 1; i < 4; i++) {
LivreType livreType = objFactory.createLivreType();
// LivreType livre = objFactory.createLivreType();
livreType.setAuteur("Auteur" + i);
livreType.setEditeur("Editeur" + i);
livreType.setTitre("Titre" + i);
livres.add(livreType);
}
} catch (Exception e) {
}
}
} |
Une fois la représentation en mémoire du document XML créée ou modifiée, il est fréquent de devoir l'envoyer dans un flux tel qu'un fichier pour conserver les modifications. Cette opération se nomme marshalling.
Pour réaliser cette opération, il faut tout d'abord obtenir un objet du type JAXBContext en utilisant la méthode newInstance(). Cette méthode demande en paramètre une chaîne de caractères indiquant le package des interfaces gérées à partir du schéma.
La méthode createMarshaller() permet d'obtenir un objet de type Marshaller. C'est cet objet qui va formater le document XML.
Il est possible de lui préciser des propriétés pour effectuer sa tache en utilisant la méthode setProperty(). Des constantes sont définies pour ces propriétés dont les principales sont :
La valeur des propriétés doit être un objet.
L'appel de la méthode marshal() formate le document dont l'objet racine est fourni en premier paramètre. Il existe plusieurs surcharges de cette méthode pour préciser où est envoyé le résultat de la génération. Le second paramètre permet de préciser cette cible : un flux en sortie, un arbre DOM, des événements SAX.
| Exemple : |
package com.jmdoudoux.test.jaxb;
import javax.xml.bind.*;
import java.io.*;
import java.util.*;
public class TestJAXB3 {
public static void main(String[] args) {
try {
ObjectFactory objFactory = new ObjectFactory();
Bibliotheque bibliotheque = (Bibliotheque) objFactory.createBibliotheque();
List livres = bibliotheque.getLivre();
for (int i = 1; i < 4; i++) {
LivreType livreType = objFactory.createLivreType();
// LivreType livre = objFactory.createLivreType();
livreType.setAuteur("Auteur" + i);
livreType.setEditeur("Editeur" + i);
livreType.setTitre("Titre" + i);
livres.add(livreType);
}
JAXBContext jaxbContext = JAXBContext.newInstance("com.jmdoudoux.test.jaxb");
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
Validator validator = jaxbContext.createValidator();
marshaller.marshal(bibliotheque, System.out);
} catch (Exception e) {
}
}
} |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <bibliotheque> <livre> <titre>Titre1</titre> <auteur>Auteur1</auteur> <editeur>Editeur1</editeur> </livre> <livre> <titre>Titre2</titre> <auteur>Auteur2</auteur> <editeur>Editeur2</editeur> </livre> <livre> <titre>Titre3</titre> <auteur>Auteur3</auteur> <editeur>Editeur3</editeur> </livre> </bibliotheque> |
JAXB 2.0 a été développé sous la JSR 222 et elle est incorporée dans Java EE 5 et dans Java SE 6.
Les fonctionnalités de JAXB 2.0 par rapport à JAXB 1.0 sont :
En plus de son utilité principale, JAXB 2.0 propose d'atteindre plusieurs objectifs :
L'utilisation de JAXB implique généralement deux étapes :

JAXB 2.0 permet toujours de mapper des objets Java dans un document XML et vice et versa. Il permet aussi de générer des classes Java à partir un schéma XML et vice et versa.

La sérialisation d'un graphe d'objets Java est effectué par une opération dite de mashalling. L'opération inverse est dite d'unmashalling. Lors de ces deux opérations, le document XML peut être validé.
JAXB 2.0 utilise de nombreuses annotations définies dans le package javax.xml.bin.annotation essentiellement pour préciser le mode de fonctionnement lors des opérations de marshaling/unmarshaling.
Ces annotations précisent le mapping entre les classes Java et le document XML. La plupart de ces annotations ont des valeurs par défaut ce qui réduit l'obligation de leur utilisation si la valeur par défaut correspond au besoin.

JAXB 2.0 permet aussi de réaliser dynamiquement à l'exécution une transformation d'un graphe d'objets en document XML et vice et versa. C'est cette fonctionnalité qui est largement utilisée dans les services web via l'API JAX-WS 2.0.
La classe abstraite JAXBContext fournie par l'API JAXB permet de gérer la transformation d'objets Java en XML et vice et versa.
JAXB 2.0 propose plusieurs outils pour faciliter sa mise en oeuvre :
L'API JAXB est contenue dans la package javax.xml.bind
JAXB 2.0 est incorporée dans Java EE 5 et dans Java SE 6.
Pour les versions antérieures de ces plateformes, il est possible d'utiliser le Java Web Services Developer Pack 2.0 (JWSDP 2.0) qui contient l'implémentation de référence de JAXB 2.0.
Avec la version fournie avec JWSDP 2.0, les bibliothèques suivantes doivent être ajoutées au classpath :
jaxb\lib\jaxb-api.jar,
jaxb\lib\jaxb-impl.jar,
jaxb\lib\jaxb-xjc.jar,
jwsdp-shared\lib\activation.jar,
sjsxp\lib\jsr173_api.jar,
sjsxp\lib\sjsxp.jar
Attention JAXB 2.0 requiert un JDK 5.0 minimum pour être utilisé.
La mise en oeuvre de JAXB requiert pour un usage standard plusieurs étapes :
L'utilisation de JAXB se fait donc en deux phases :

L'utilisation de JAXB met en oeuvre plusieurs éléments :
Les avantages d'utiliser JAXB sont nombreux :
Pour permettre l'utilisation et la manipulation d'un document XML, JAXB propose de générer un ensemble de classes à partir du schéma XML du document.

Chaque implémentation de JAXB doit fournir un outil (binding compiler) qui permet la génération de classes et interfaces à partir d'un schema (binding a schema).
L'implémentation de référence fournit l'outil xjc pour générer les classes à partir d'un schéma XML.
L'utilisation la plus simple de l'outil xjc est de lui fournir simplement le fichier qui contient le schéma XML du document à utiliser.
| Exemple : |
xjc biblio.xsd |
L'outil xjc possède plusieurs options dont voici les principales :
Option |
Rôle |
-p nom_package |
Précise le package qui va contenir les classes générées |
-d répertoire |
Précise le répertoire qui va contenir les classes générées |
-nv |
Inhibe la validation du schéma |
-b fichier |
Précise un fichier de configuration |
-classpath chemin |
Précise le classpath |
Le compilateur génère des classes en correspondance avec le schéma XML fourni à l'outil.
| Exemple : biblio.xsd |
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.jmdoudoux.com/test/jaxb"
xmlns:tns="http://www.jmdoudoux.com/test/jaxb"
elementFormDefault="qualified">
<xs:element name="bibliotheque">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="livre">
<xs:complexType>
<xs:sequence>
<xs:element name="titre" type="xs:string" />
<xs:element name="auteur">
<xs:complexType>
<xs:sequence>
<xs:element name="nom" type="xs:string" />
<xs:element name="prenom" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="editeur" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema> |
| Exemple : exécution de la commande xjc |
C:\Documents and Settings\jmd\workspace\TestJAXB>xjc -d src biblio.xsd parsing a schema... compiling a schema... com\jmdoudoux\test\jaxb\Bibliotheque.java com\jmdoudoux\test\jaxb\ObjectFactory.java com\jmdoudoux\test\jaxb\package-info.java |
Trois entités sont générées dans le répertoire src :
Par défaut, le package utilisé est déduit de l'espace de nommage défini dans le schéma.

Chaque classse qui encapsule un type complexe du schéma possède des getter et setter sur les éléments du schéma.
La fabrique permet de créer des instances de chacun des types d'objet correspondant à un type complexe du schéma. Cette fabrique est particulièrement utile lors de la création d'un nouveau document XML : le graphe d'objets est créé en ajoutant des instances des objets retournées par cette fabrique.
Les classes générées sont dépendantes de l'implémentation de JAXB utilisée : il est préférable d'utiliser les classes générées par une implémentation avec cette implémentation.
Par défaut, JAXB utilise des règles pour définir chaque entité incluse dans le schéma (element et complexType définis dans le schéma).
JAXB fournit une API qui permet à l'exécution d'effectuer les opérations de transformation d'un document XML en un graphe d'objets utilisant les classes générées et vice et versa (unmashalling/marshalling) ainsi que des opérations de validation.
L'objet principal pour les opérations de transformation est l'objet JAXBContext : il permet d'utiliser l'API JAXB. Pour obtenir une instance de cet objet, il faut utiliser la méthode statique newInstance() en lui passant en paramètre le ou les packages contenant les classes générées à utiliser. Dans le cas où plusieurs packages doivent être précisés, il faut les séparer par une virgule.
Une autre surcharge de la méthode newInstance() attend en paramètre la classe qui encapsule la racine du document.
| Exemple : |
JAXBContext jc = JAXBContext.newInstance("com.jmdoudoux.test.jaxb"); |
L'API JAXB propose de transformer un document XML en un ensemble d'objets qui vont encapsuler les données et la hiérarchie du document. Ces objets sont des instances des classes générées à partir du schéma XML.

La création des objets nécessite la création d'un objet de type JAXBContext en utilisant la méthode statique newInstance().
Il faut ensuite instancier un objet de type Unmarshaller qui va permettre de transformer un document XML en un ensemble d'objets. Un telle instance est obtenue en utilisant la méthode createUnmarshaller() de la classe JAXBContext.
| Exemple : |
Unmarshaller unmarshaller = jc.createUnmarshaller(); |
La méthode unmarshal() de la classe Unmarshaller se charge de traiter un document XML et retourne un objet du type complexe qui encapsule la racine du document XML. Elle possède de nombreuses surcharges à utiliser en fonction des besoins.
| Exemple : |
Bibliotheque bibliotheque = (Bibliotheque) unmarshaller.unmarshal(new File("biblio.xml")); |
A partir de cet objet, il est possible d'obtenir et de modifier des données encapsulées dans les différents objets créés à partir des classes générées et du contenu du document. Chacun de ces objets possède des getter et des setter sur leur noeud direct.
| Exemple : |
List<Livre> livres = bibliotheque.getLivre();
for (int i = 0; i < livres.size(); i++) {
Livre livre = livres.get(i);
System.out.println("Livre ");
System.out.println("Titre : " + livre.getTitre());
System.out.println("Auteur : " + livre.getAuteur().getNom()
+ " " +livre.getAuteur().getPrenom());
System.out.println("Editeur : " + livre.getEditeur());
System.out.println(); |
Il est possible de demander la validation du document en utilisant la méthode setValidating() de la classe Unmarshaller. Cela permet de demander la validation du document à traiter avec le schéma
| Exemple : |
unmarshaller.setValidating(true); |
| Exemple : mise en oeuvre des entités générées à partir schéma biblio.xsd |
package com.jmdoudoux.test.jaxb;
import java.io.File;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import com.jmdoudoux.test.jaxb.Bibliotheque.Livre;
public class TestJAXB2 {
public static void main(String[] args) {
try {
JAXBContext jc = JAXBContext.newInstance("com.jmdoudoux.test.jaxb");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Bibliotheque bibliotheque = (Bibliotheque) unmarshaller.unmarshal(
new File("biblio.xml"));
List<Livre> livres = bibliotheque.getLivre();
for (int i = 0; i < livres.size(); i++) {
Livre livre = livres.get(i);
System.out.println("Livre ");
System.out.println("Titre : " + livre.getTitre());
System.out.println("Auteur : " + livre.getAuteur().getNom()
+ " " +livre.getAuteur().getPrenom());
System.out.println("Editeur : " + livre.getEditeur());
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
}
} |
| Exemple : le document XML utilisé |
<?xml version="1.0" encoding="UTF-8"?>
<tns:bibliotheque xmlns:tns="http://www.jmdoudoux.com/test/jaxb"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jmdoudoux.com/test/jaxb biblio.xsd ">
<tns:livre>
<tns:titre>titre 1</tns:titre>
<tns:auteur>
<tns:nom>nom 1</tns:nom>
<tns:prenom>prenom 1</tns:prenom>
</tns:auteur>
<tns:editeur>editeur 1</tns:editeur>
</tns:livre>
<tns:livre>
<tns:titre>titre 2</tns:titre>
<tns:auteur>
<tns:nom>nom 2</tns:nom>
<tns:prenom>prenom 2</tns:prenom>
</tns:auteur>
<tns:editeur>editeur 2</tns:editeur>
</tns:livre>
<tns:livre>
<tns:titre>titre 3</tns:titre>
<tns:auteur>
<tns:nom>nom 3</tns:nom>
<tns:prenom>prenom 3</tns:prenom>
</tns:auteur>
<tns:editeur>editeur 3</tns:editeur>
</tns:livre>
</tns:bibliotheque> |
| Résultat : |
Livre Titre : titre 1 Auteur : nom 1 prenom 1 Editeur : editeur 1 Livre Titre : titre 2 Auteur : nom 2 prenom 2 Editeur : editeur 2 Livre Titre : titre 3 Auteur : nom 3 prenom 3 Editeur : editeur 3 |
JAXB permet de créer un document XML à partir d'un graphe d'objets : cette opération est nommée marshalling. Une opération de mashalling est l'opération inverse de l'opération d'unmarshalling.
Ce graphe d'objets peut être issu d'une opération de type unmarshalling (construction à partir d'un document XML existant) ou issu d'une création de toutes pièces de l'ensemble des objets. Dans le premier cas cela correspond à une modification du document et dans le second cas à une création de document.

La création des objets nécessite la création d'un objet de type JAXBContext en utilisant la méthode statique newInstance().
Il faut ensuite instancier un objet de type Marshaller qui va permettre de transformer un document XML en un ensemble d'objets. Une telle instance est obtenue en utilisant la méthode createMarshaller() de la classe JAXBContext.
| Exemple : |
Marshaller marshaller = jc.createMarshaller(); |
La méthode marshal() de la classe marshaller se charge de créer un document XML à partir d'un graphe d'objets dont l'objet racine lui est fourni en paramètre.
La méthode marshal() possède plusieurs surcharges qui permettent de préciser la forme du document XML généré :
L'objet Mashaller possède des propriétés qu'il est possible de valoriser en utilisant la méthode setProperty(). Les spécifications de JAXB proposent des propriétés qui doivent être obligatoirement supportées par l'implémentation. Chaque implémentation est libre de proposer des propriétés supplémentaires.
| Exemple : demander le formattage du document créé |
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
Il est possible de demander la validation du graphe d'objets. La validation n'est pas intégrée à l'opération de mashalling mais elle est effectuée à la demande séparément
La validation s'effectue en utilisant la classe Validator. Une instance de cette classe est obtenue en utilisation la méthode createValidator() de la classe JAXBContext.
| Exemple : |
Validator validator = jaxbContext.createValidator(); |
Pour valider le graphe d'objets vis-à-vis du schéma, il faut utiliser la méthode validate() de la classe Validator en lui passant en paramètre l'objet qui encapsule la racine du document.
JAXB permet de mapper un document XML vers une ou plusieurs classes annotées sans être obligé d'utiliser un schéma XML. Dans ce cas, le développeur a la charge d'écrire la ou les classes annotées requises.

Il n'est donc pas nécessaire d'utiliser des classes générées par le compilateur de schéma mais dans ce cas, la ou les classes doivent être crées manuellement en utilisant les annotations adéquates.
La classe qui encapsule la racine du document doit être annotée avec l'annotation @XmlRootElement. Une exception de type javax.xml.bind.MarshalException est levée par JAXB si la classe racine ne possède pas cette annotation.
| Exemple : |
javax.xml.bind.MarshalException - with linked exception: [com.sun.istack.internal.SAXException2: unable to marshal type "com.jmdoudoux.test.jaxb. Personne" as an element because it is missing an @XmlRootElement annotation] |
JAXB utilise des comportements par défaut qui ne nécessitent de la part du développeur que de définir des comportements particuliers si la valeur par défaut ne convient pas.
| Exemple : un bean utilisé avec JAXB |
package com.jmdoudoux.test.jaxb;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Personne {
private String nom;
private String prenom;
private int taille;
private Date dateNaiss;
public Personne() {
}
public Personne(String nom, String prenom, int taille, Date dateNaiss) {
super();
this.nom = nom;
this.prenom = prenom;
this.taille = taille;
this.dateNaiss = dateNaiss;
}
public Date getDateNaiss() {
return dateNaiss;
}
public void setDateNaiss(Date dateNaiss) {
this.dateNaiss = dateNaiss;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public int getTaille() {
return taille;
}
public void setTaille(int taille) {
this.taille = taille;
}
} |
La création du document nécessite la création d'un objet de type JAXBContext en utilisant la méthode statique newInstance().
Il faut ensuite créer un objet de type Marshaller à partir du contexte et appeler sa méthode marshall pour générer le document.
| Exemple : marshalling de l'objet |
package com.jmdoudoux.test.jaxb;
import java.util.Date;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class TestJAXB1 {
public static void main(String[] args) {
try {
JAXBContext context = JAXBContext.newInstance(Personne.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Personne p = new Personne("nom1", "prenom1", 175, new Date());
m.marshal(p, System.out);
} catch (JAXBException ex) {
ex.printStackTrace();
}
}
} |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <personne> <dateNaiss>2007-01-16T17:03:31.213+01:00</dateNaiss> <nom>nom1</nom> <prenom>prenom1</prenom> <taille>175</taille> </personne> |
Une des classes générées à partir du schéma se nomme ObjectFactory : c'est une fabrique d'objets pour les classes générées qui encapsulent des données d'un document respectant le schéma.
Pour créer un document XML en utilisant ces classes, il faut mettre en oeuvre plusieurs étapes.
La création du document nécessite la création d'un objet de type JAXBContext en utilisant la méthode statique newInstance().
Il faut ensuite créer le graphe d'objets en utilisant la classe ObjectFactory pour instancier les différents objets et valoriser les données de ces objets en utilisant les setter.
Il faut créer un objet de type Marshaller à partir du contexte et appeler sa méthode marshall pour générer le document.
| Exemple : |
package com.jmdoudoux.test.jaxb;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class TestJAXB3 {
public static void main(String[] args) {
try {
JAXBContext context = JAXBContext.newInstance(Bibliotheque.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ObjectFactory fabrique = new ObjectFactory();
Bibliotheque bibliotheque = fabrique.createBibliotheque();
Bibliotheque.Livre livre = fabrique.createBibliothequeLivre();
livre.setEditeur("editeur 1");
livre.setTitre("titre 1");
Bibliotheque.Livre.Auteur auteur = fabrique
.createBibliothequeLivreAuteur();
auteur.setNom("nom 1");
auteur.setPrenom("prenom 1");
livre.setAuteur(auteur);
bibliotheque.getLivre().add(livre);
m.marshal(bibliotheque, System.out);
} catch (JAXBException ex) {
ex.printStackTrace();
}
}
} |
JAXB propose des fonctionnalités pour configurer finement les traitements qu'il propose.
JAXB utilise des traitements par défaut qu'il est possible de configurer différemment en utilisant soit les annotations soit un fichier de configuration qui sera fourni au compilateur.
Les classes générées peuvent aussi être configurées, notamment le nom du package et des classes utilisées.
Par défaut, le générateur de classes à partir du schéma utilise des conventions de nommage des différentes entités générées à partir des noms utilisés dans le schéma. Il est possible de configurer de façon différente les noms utilisés.
Les spécifications JAXB décrivent de façon précise comment les éléments d'un schéma sont transformés en classes Java. Il est possible de préciser des informations particulières dans le schéma pour modifier ce comportement par défaut.
Ces informations peuvent être incluse directement dans le schéma ou fournie dans un fichier dédié. Dans le schéma, ces informations sont fournies dans un tag <annotation> qui contient un tag fils <appinfo>.
| Exemple : biblio2.xsd |
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.jmdoudoux.com/test/jaxb/perso"
xmlns:tns="http://www.jmdoudoux.com/test/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="1.0"
elementFormDefault="qualified">
<xs:element name="bibliotheque">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="livre">
<xs:complexType>
<xs:sequence>
<xs:element name="titre" type="xs:string" />
<xs:element name="auteur">
<xs:complexType>
<xs:sequence>
<xs:element name="nom"
type="xs:string" />
<xs:element name="prenom"
type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="editeur" type="xs:string">
<!--
Personnalisation de la propriété editeur en nomEditeur
-->
<xs:annotation>
<xs:appinfo>
<jaxb:property name="nomEditeur" />
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema> |
| Exemple : génération des classes à partir du schéma annoté |
C:\Documents and Settings\jmd\workspace\TestJAXB>xjc -d src -extension biblio2.x sd parsing a schema... compiling a schema... com\jmdoudoux\test\jaxb\perso\Bibliotheque.java com\jmdoudoux\test\jaxb\perso\ObjectFactory.java com\jmdoudoux\test\jaxb\perso\package-info.java |
L'option -extension du générateur de classes autorise l'outil à utiliser des extensions proposées par l'implémentation de JAXB utilisée. Sans cette option, l'outil utilise le mode strict et une exception est levée si une extension est utilisée.
| Exemple : la classe Livre générée à partir du schéma |
...
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"titre",
"auteur",
"nomEditeur"
})
public static class Livre {
@XmlElement(required = true)
protected String titre;
@XmlElement(required = true)
protected Bibliotheque.Livre.Auteur auteur;
@XmlElement(name = "editeur", required = true)
protected String nomEditeur;
...
/**
* Gets the value of the nomEditeur property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getNomEditeur() {
return nomEditeur;
}
/**
* Sets the value of the nomEditeur property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setNomEditeur(String value) {
this.nomEditeur = value;
}
... |
JAXB propose de nombreuses fonctionnalités de configuration : consultez les spécifications pour de plus amples détails.
La configuration de la transformation d'un document XML en objets Java est réalisée grâce à l'utilisation d'annotations dédiées dans les classes Java.
De nombreuses annotations sont définies par JAXB 2.0 dont voici les principales :
XmlAccessorOrder |
Ordonner les champs et propriétés dans la classe |
XmlAccessorType |
Préciser comment un champ ou une propriété est sérialisé |
XmlAnyAttribute |
|
XmlAnyElement |
|
XmlAttachmentRef |
|
XmlAttribute |
Convertir une propriété en un attribut dans le document XML |
XmlElement |
Convertir une propriété en un élément dans le document XML |
XmlElementDecl |
Associer une fabrique à une élément XML |
XmlElementRef |
|
XmlElementRefs |
|
XmlElements |
|
XmlElementWrapper |
Créer un élément père dans le document XML pour des collections d'éléments |
XmlEnum |
|
XmlEnumValue |
|
XmlID |
|
XmlIDREF |
|
XmlInlineBinaryData |
|
XmlList |
|
XmlMimeType |
|
XmlMixed |
|
XmlNs |
Associer un prefixe d'un espace de nommage à un URI |
XmlRegistry |
Marquer une classe comme possédant une ou des méthodes annotées avec @XmlElementDecl |
XmlRootElement |
Associer une classe ou une énumération à un élément XML |
XmlSchema |
Associer un espace de nommage à un package |
XmlSchemaType |
Associer un type Java ou une énumeration à un type défini dans un schéma |
XmlSchemaTypes |
|
XmlTransient |
Marquer une entité pour ne pas être mappée dans le document XML |
XmlType |
|
XmlValue |
|
Ces annotations sont définies dans le package javax.xml.bind.annotation.
L'annotation @XmlRootElement peut être utilisée sur une classe pour préciser que cette classe sera le tag racine du document XML. Chaque attribut de la classe sera un tag fils dans le document XML. L'attribut namespace de l'annotation @XmlRootElement permet de préciser l'espace de nommage.
L'annotation XmlTransient permet d'ignorer une entité dans le mapping.
| Exemple : |
@XmlTransient
public String getNom() {
return nom;
} |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<personne xmlns="http://www.jmdoudoux.com/test/jaxb">
<dateNaiss>2007-06-21T15:18:28.809+02:00</dateNaiss>
<prenom>prenom1</prenom>
<taille>175</taille>
</personne> |
L'annotation XmlAttribute permet de mapper une propriété sous la forme d'un attribut et fournir des précisions sur la configuration de cet attribut
| Exemple : |
@XmlAttribute (name="nomPrincipal")
public String getNom() {
return nom; |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <personne xmlns="http://www.jmdoudoux.com/test/jaxb" nom="nom1"> <dateNaiss>2007-06-21T15:20:34.377+02:00</dateNaiss> <prenom>prenom1</prenom> <taille>175</taille> </personne> |
Pour les collections, il est possible d'utiliser l'annotation @XmlElementWrapper pour définir un élement père qui encapsule les occurrences de la collection et d'utiliser l'annotation XmlElement pour préciser le nom de chaque élément de la collection
| Exemple : |
@XmlElementWrapper(name = "Residence") @XmlElement(name = "adresse") protected List<Adresse> adresses = new ArrayList<Adresse>(); |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<personne xmlns="http://www.jmdoudoux.com/test/jaxb">
<Residence>
<adresse>
<codePostal>54000</codePostal>
<ligne1>ligne1</ligne1>
<ligne2>ligne2</ligne2>
<pays>pays1</pays>
<ville>ville1</ville>
</adresse>
</Residence>
<dateNaiss>2007-06-21T15:34:35.547+02:00</dateNaiss>
<nom>nom1</nom>
<prenom>prenom1</prenom>
<taille>175</taille>
</personne> |
Il est possible de configurer l'ordre des éléments
| Exemple : |
@XmlRootElement
@XmlType(propOrder = {"nom", "prenom", "taille",
"dateNaiss", "adresses"})
public class Personne {
private String nom;
private String prenom;
private int taille;
private Date dateNaiss;
@XmlElementWrapper(name = "Residence")
@XmlElement(name = "adresse")
protected List<Adresse> adresses = new ArrayList<Adresse>(); |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<personne xmlns="http://www.jmdoudoux.com/test/jaxb">
<nom>nom1</nom>
<prenom>prenom1</prenom>
<taille>175</taille>
<dateNaiss>2007-06-21T15:44:12.815+02:00</dateNaiss>
<Residence>
<adresse>
<codePostal>54000</codePostal>
<ligne1>ligne1</ligne1>
<ligne2>ligne2</ligne2>
<pays>pays1</pays>
<ville>ville1</ville>
</adresse>
</Residence>
</personne> |
Il est possible de définir des classes de type Adapter qui permettent de personnaliser la façon dont un objet est serialisé/desérialisé dans le document XML.
Ces adapters héritent de la classe javax.xml.bind.annotation.adapters.XmlAdapter. Il suffit de redéfinir les méthodes marshal() et unmashal(). Ces méthodes seront utilisées à l'exécution par l'API JAXB lors des transformations.
| Exemple : la classe DateAdapter |
package com.jmdoudoux.test.jaxb;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<String, Date> {
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
public Date unmarshal(String date) throws Exception {
return df.parse(date);
}
public String marshal(Date date) throws Exception {
return df.format(date);
}
} |
L'annotation @XmlJavaTypeAdapter permet de préciser la classe de type Adapter qui sera à utiliser plutôt que d'utiliser la conversion par défaut.
| Exemple : |
package com.jmdoudoux.test.jaxb;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlType(propOrder = {"nom", "prenom", "taille",
"dateNaiss", "adresses"})
public class Personne {
private String nom;
private String prenom;
private int taille;
private Date dateNaiss;
@XmlElementWrapper(name = "Residence")
@XmlElement(name = "adresse")
protected List<Adresse> adresses = new ArrayList<Adresse>();
public Personne() {
}
public Personne(String nom, String prenom, int taille, Date dateNaiss) {
super();
this.nom = nom;
this.prenom = prenom;
this.taille = taille;
this.dateNaiss = dateNaiss;
}
@XmlJavaTypeAdapter(DateAdapter.class)
public Date getDateNaiss() {
return dateNaiss;
}
public void setDateNaiss(Date dateNaiss) {
this.dateNaiss = dateNaiss;
} |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<personne xmlns="http://www.jmdoudoux.com/test/jaxb">
<nom>nom1</nom>
<prenom>prenom1</prenom>
<taille>175</taille>
<dateNaiss>22/06/2007</dateNaiss>
<Residence>
<adresse>
<codePostal>54000</codePostal>
<ligne1>ligne1</ligne1>
<ligne2>ligne2</ligne2>
<pays>pays1</pays>
<ville>ville1</ville>
</adresse>
</Residence>
</personne> |
Ceci ne présente qu'une toute petite partie des fonctionnalités proposées par JAXB. Pour de plus amples informations, consultez les spécifications de JAXB.
L'outil schemagen fourni avec l'implémentation par défaut permet de générer un schéma XML à partir de classes annotées compilées
| Exemple : |
C:\Documents and Settings\jmd\workspace\TestJAXB>schemagen -cp ./bin com.jmdoudo ux.test.jaxb.Personne Note: Writing schema1.xsd |
| Résultat : |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="personne" type="personne"/>
<xs:complexType name="personne">
<xs:sequence>
<xs:element name="nom" type="xs:string" minOccurs="0"/>
<xs:element name="prenom" type="xs:string" minOccurs="0"/>
<xs:element name="taille" type="xs:int"/>
<xs:element name="dateNaiss" type="xs:string" minOccurs="0"/>
<xs:element name="Residence" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="adresse" type="adresse" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="adresse">
<xs:sequence>
<xs:element name="codePostal" type="xs:string" minOccurs="0"/>
<xs:element name="ligne1" type="xs:string" minOccurs="0"/>
<xs:element name="ligne2" type="xs:string" minOccurs="0"/>
<xs:element name="pays" type="xs:string" minOccurs="0"/>
<xs:element name="ville" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema> |
|
|
|
|
|
|
Développons en Java v 1.60 | ||
| Copyright (C) 1999-2011 Jean-Michel DOUDOUX |