11 - java et xml - jaxb

25
Java et XML - JAXB Chapitres traités Qu'est ce que le « Data Binding » ou association de données ? Le XML est aujourd'hui un format d'échange de données très utilisé. Il possède de nombreux avantages : il est standard, simple, et surtout facile à lire. Il peut être lu par un homme, mais ce qui le plus intéressant c'est qu'il peut être lu par un ordinateur. En effet, la puissance du XML repose sur le fait qu'il peut être analysé par un programme et le contenu de ce flux est compris par la machine. La structure de ce langage permet en effet de comprendre les relations entre toutes ces données. De ce fait, les programmeurs ont réalisé de nombreuses API permettant d'accéder aux données XML à travers leurs langages favoris (DOM et SAX par exemple en Java). Néanmoins, ces dernières ont des inconvénients. Tous d'abord, il faut étudier et apprendre une nouvelle API. Puis, ils sont trop généraux. C'est-à-dire que le programmeur doit adapter le code à son application à chaque fois qu'il veut accéder à des données XML. Ensuite, il faut qu'il crée lui-même toutes les classes permettant de gérer ces nouvelles données dans son programme, cela lui prend donc beaucoup de temps. Pour remédier à ces inconvénients, il existe le « Data Binding » également appelé en français : association de données . En java, Sun a réalisé une API nommée JAXB (Java Architecture for XML Binding) pour simplifier les processus de transformation d’objets Java en fichier XML, et de fichier XML en objets Java. 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. Qu'est ce que le « Data Binding » ou association de données ? Le Data Binding est une technologie permettant d'automatiser la transformation d'un modèle de données en un modèle de données objets dans un langage de programmation. Autrement dit, il permet par exemple de convertir les fichiers XML en instances de classes Java. Pour réaliser cela, il y a trois étapes : 1. La génération de classes. 2. Le rassemblement des données. 3. La redistribution des données Le schéma suivant résume assez bien le principe : un document XML suit les règles de grammaire du « schema », ce dernier une fois compilé permet de créer une classe correspondante. Cette dernière permettra de créer une instance d'objet correspondant :

Upload: pablo-sene

Post on 25-Nov-2015

49 views

Category:

Documents


4 download

TRANSCRIPT

  • Java et XML - JAXB

    Chapitres traits Qu'est ce que le Data Binding ou association de donnes ?

    Le XML est aujourd'hui un format d'change de donnes trs utilis. Il possde de nombreux avantages : il est standard, simple, et surtout facile lire. Il peut tre lu par un homme, mais ce qui le plus intressant c'est qu'il peut tre lu par un ordinateur. En effet, la puissance du XML reposesur le fait qu'il peut tre analys par un programme et le contenu de ce flux est compris par la machine. La structure de ce langage permet eneffet de comprendre les relations entre toutes ces donnes.

    De ce fait, les programmeurs ont ralis de nombreuses API permettant d'accder aux donnes XML travers leurs langages favoris (DOM et SAXpar exemple en Java). Nanmoins, ces dernires ont des inconvnients. Tous d'abord, il faut tudier et apprendre une nouvelle API. Puis, ils sont

    trop gnraux. C'est--dire que le programmeur doit adapter le code son application chaque fois qu'il veut accder des donnes XML. Ensuite, il faut qu'il cre lui-mmetoutes les classes permettant de grer ces nouvelles donnes dans son programme, cela lui prend donc beaucoup de temps.

    Pour remdier ces inconvnients, il existe le Data Binding galement appel en franais : association de donnes. En java, Sun a ralis une API nomme JAXB (JavaArchitecture for XML Binding) pour simplifier les processus de transformation dobjets Java en fichier XML, et de fichier XML en objets Java.

    JAXB est une spcification qui permet de faire correspondre un document XML un ensemble de classes et vice et versa via des oprations de srialisation/dsrialisation nommemarshaling/unmarshaling.

    JAXB permet aux dveloppeurs de manipuler un document XML sans avoir connatre XML ou la faon dont un document XML est traite comme cela est le cas avec SAX, DOMou STAX.

    La manipulation du document XML se fait en utilisant des objets prcdemment gnrs partir d'une DTD pour JAXB 1.0 et d'un schma XML du document traiter pour JAXB2.0.

    Qu'est ce que le Data Binding ou association de donnes ?

    Le Data Binding est une technologie permettant d'automatiser la transformation d'un modle de donnes en un modle de donnes objets dans un langage de programmation. Autrementdit, il permet par exemple de convertir les fichiers XML en instances de classes Java.

    Pour raliser cela, il y a trois tapes :

    1. La gnration de classes.

    2. Le rassemblement des donnes.

    3. La redistribution des donnes

    Le schma suivant rsume assez bien le principe : un document XML suit les rgles de grammaire du schema , ce dernier une fois compil permet de crer une classecorrespondante. Cette dernire permettra de crer une instance d'objet correspondant :

  • JAXB

    JAXB est l'acronyme de Java Architecture for XML Binding. Le but de l'API et des spcifications JAXB est de faciliter la manipulation d'un document XML en gnrant un ensemble declasses qui fournissent un niveau d'abstraction plus lev que l'utilisation de JAXP (SAX ou DOM).

    Avec ces deux API, SAX et DOM, toute la logique de traitements des donnes contenues dans le document est crire.

    JAXB au contraire fournit un outil qui analyse un schma XML et gnre partir de ce dernier un ensemble de classes qui vont encapsuler les traitements de manipulation dudocument. Le grand avantage est de fournir au dveloppeur un moyen de manipuler un document XML sans connatre XML ou les technologies d'analyse. Toutes lesmanipulations se font au travers d'objets java. Ces classes sont utilises pour faire correspondre le document XML dans des instances de ces classes et vice et versa : ces oprationsse nomment respectivement unmarshalling et marshalling.

    JAXB 2.0

    JAXB 2.0 a t dvelopp sous la JSR 222 et elle est incorpore dans Java EE 5 et dans Java SE 6. Les fonctionnalits de JAXB 2.0 par rapport JAXB 1.0 sont :

    1. Support uniquement des schmas XML (les DTD ne sont plus supportes).

    2. Mise en oeuvre des annotations.

    3. Assure la correspondance bidirectionelle entre un schma XML et le bean correspondant.

    4. Utilisation de fonctionnalits proposes par Java 5 notamment les generiques et les numrations.

    5. Le nombre d'entits gnres est moins important : JAXB 2.0 gnre une classe pour chaque complexType du schema alors que JAXB 1.0 gnre une interface et une classe quiimplmente cette interface. Une mthode de la classe ObjectFactory est gnre pour renvoye une instance de cette classe.

    En plus de son utilit principale, JAXB 2.0 propose d'atteindre plusieurs objectifs :

    1. tre facile utiliser pour consulter et modifier un document XML sans connaissance ni de XML ni de techniques de traitement de documents XML.

    2. tre configurable : JAXB met en oeuvre des fonctionnalits par dfaut qu'il est possible de modifier par configuration pour rpondre ces propres besoins.

    3. S'assurer que la cration d'un document XML partir d'objets et retransformer ce document en objets donne le mme ensemble d'objets.

    4. Pouvoir valider un document XML ou les objets qui encapsulent un document sans avoir crire le document correspondant.

    5. tre portable : chaque implmentation doit au minimum mettre en oeuvre les spcifications de JAXB.

    L'utilisation de JAXB implique gnralement deux tapes :

    1. Gnration des classes et interfaces partir du schma XML.

    2. Utilisation des classes gnres et de l'API JAXB pour transformer un document XML en graphe d'objets et vice et versa, pour manipuler les donnes dans le graphe d'objets etpour valider le document.

  • Srialisation

    La srialisation d'un graphe d'objets Java est effectu par une opration dite de mashalling. L'opration inverse est dite d'unmashalling. Lors de ces deux oprations, le document XMLpeut tre valid.

    L'API JAXB

    L'API JAXB propose un framework compos de classes regroupes dans trois packages :

    1. javax.xml.bind : Contient les interfaces principales et la classe JAXBContext.

    2. javax.xml.bind.util : Contient des utilitaires.

    3. javax.xml.bind.helper : Contient une implmentation partielle de certaines interfaces pour faciliter le dveloppement d'une implmentation des spcifications de JAXB.

    4. javax.xml.bin.annotation : Gestion des annotations pour prciser le mapping entre les classes Java et le document XML correspondant.

    Annotations

    JAXB 2.0 utilise de nombreuses annotations dfinies dans le package javax.xml.bin.annotation essentiellement pour prciser le mode de fonctionnement lors des oprations demarshaling/unmarshaling.

    Ces annotations prcisent le mapping entre les classes Java et le document XML. La plupart de ces annotations ont des valeurs par dfaut ce qui rduit l'obligation de leurutilisation si la valeur par dfaut correspond au besoin.

    Transformations

    JAXB 2.0 permet aussi de raliser dynamiquement l'excution une transformation d'un graphe d'objets en document XML et vice et versa. C'est cette fonctionnalit qui est largementutilise dans les services web via l'API JAXWS 2.0. La classe abstraite JAXBContext fournie par l'API JAXB permet de grer la transformation d'objets Java en XML et vice et versa.

    Outils de JAXB 2.0

    JAXB 2.0 propose plusieurs outils pour faciliter sa mise en oeuvre :

    1. Un gnrateur de classes Java (schema compiler) partir d'un schma XML nomm xjc dans l'implmentation de rfrence. Ces classes gnres mettent en oeuvre lesannotations de JAXB.

    2. Un gnrateur de schma XML (schema generator) partir d'un graphe d'objets nomm schemagen dans l'implmentation de rfrence.

    L'API JAXB est contenue dans la package javax.xml.bind.

  • La mise en oeuvre de JAXB 2.0

    La mise en oeuvre de JAXB requiert pour un usage standard plusieurs tapes :

    1. La gnration des classes en utilisant l'outil xjc de JAXB partir d'un schma du document XML.

    2. Ecriture de code utilisant les classes gnres et l'API JAXB pour :Transformer un document XML en objets Java.

    Modifier des donnes encapsules dans le graphe d'objets.

    Transformer le graphe d'objets en un document XML avec une validation optionnelle du document.

    3. Compilation du code gnr.

    4. Excution de l'application.

    Utilisation de JAXB 2.0

    L'utilisation de JAXB se fait donc en deux phases :

    1. Gnrer des classes partir d'un schma XML et utiliser ces classes dans le code de l'application.

    2. l'excution de l'application, le document XML est transform en graphe d'objets, les donnes de ces objets peuvent tre modifies puis le document XML peut tre regnr partir des objets.

    L'utilisation de JAXB met en oeuvre plusieurs lments :

    1. Une ou plusieurs classes annotes qui vont encaspules des donnes du document XML.

    2. Un schma XML (optionnel) : c'est un document XML qui dcrit la structure des lments, attributs et entits d'un document XML. Le but d'un schma XML est similaire celuid'une DTD mais le schma propose une description plus riche et plus fine. Ce schma peut ventuellement tre enrichi de donnes de configurations concernant les classes gnrer.

    3. Un outil (optionnel) qui gnre les classes annotes partir d'un schma avec ventuellement un fichier de configuration pour configurer les classes gnrer.

    4. Une API utilise l'excution pour transformer un document XML en un ensemble d'objets du type des classes annotes et vice et versa et permettre des validations.

    5. Un document XML qui sera lu et/ou crit en fonction des traitements raliser.

    Avantages

    Les avantages d'utiliser JAXB sont nombreux :

    1. Facilite la manipulation de document XML dans une application Java.

    2. Manipulation du document XML au travers d'objets : aucune connaissance de XML ou de la manire de traiter un document n'est requise.

    3. Un document XML peut tre cr en utilisant les classes gnres.

    4. Les traitements de JAXB peuvent tre configurs.

    5. Les ressources requises par le graphe d'objets utilis par JAXB sont moins importantes qu'avec DOM.

    Inconvnients

    Si vous devez crer des classes directement partir d'un document XML, vous devez imprativement possder le Schma XML correspondant (avec l'extension xsd). Si vous n'avez pas leSchma XML, cela peut poser quelques difficults. C'est l'inconvnient de cette technologie.

    Toutefois, il existe des logiciels libres, comme Liquid XML Studio, qui savent crer un Schma directement partir du document XML correspondant. Ils proposent alors desvaleurs par dfaut que vous pouvez par la suite modifier au travers des proprits proposes dans l'diteur intgr.

  • Gnrer des classes partir d'un schma

    Pour permettre l'utilisation et la manipulation d'un document XML, JAXB propose de gnrer un ensemble de classes partir du schema XML du document.

    Chaque implmentation de JAXB doit fournir un outil (binding compiler) qui permet la gnration de classes et interfaces partir d'un schema (binding a schema).

    Exemple de document XML avec son Schma XML associ

    Je vous propose, pour la suite de cette tude, de prendre un exemple concret, et surtout trs simple. J'aimerais pouvoir mettre en oeuvre un logiciel qui trace des formes, des carrs oudes cercles, dans la partie principale d'une application graphique fentre.

    Il doit tre possible de rcuprer l'ensemble des formes tracer au moyen, par exemple, du document XML ci-dessous :

    En utilisant le logiciel Liquid XML Studio, et en faisant les rglages ncessaires, voici le Schma XML correspondant :

  • La commande xjc

    Comme nous l'avons vu, l'implmentation de rfrence fournit l'outil xjc pour gnrer les classes partir d'un schma XML. L'utilisation la plus simple de l'outil xjc est de lui fournirsimplement le fichier qui contient le schma XML du document utiliser.

    xjc Formes.xsd

    L'outil xjc possde plusieurs options dont voici les principales :

    Option Rle

    -p nom_package Prcise le package qui va contenir les classes gnres

    -d rpertoire Prcise le rpertoire qui va contenir les classes gnres

    -nv Inhibe la validation du schma

    -b fichier Prcise un fichier de configuration

    -classpath chemin Prcise le classpath

    Les classes gnres

    Le compilateur gnre des classes en correspondance avec le Schma XML fourni l'outil.

  • Deux entits sont gnres dans le rpertoire generated :

    1. Formes.java : classes qui encaspulent le document XML. Chaque classse qui encapsule un type complexe du schma possde des getter et setter sur les lments du schma.

    2. ObjectFactory.java : fabrique qui permet d'instancier des objets utiliss lors du mapping. La fabrique permet de crer des instances de chacun des types d'objet correspondant un type complexe du schma. Cette fabrique est particulirement utile lors de la cration d'un nouveau document XML : le graphe d'objets est cr en ajoutant des instances desobjets retournes par cette fabrique.

    Les classes gnres sont dpendantes de l'implmentation de JAXB utilise : il est prfrable d'utiliser les classes gnres par une implmentation avec cet outil. Par dfaut,JAXB utilise des rgles pour dfinir chaque entit incluse dans le schema (element et complexType dfini dans le schma).

    Formes.java (sans les commentaires)

    package jaxb; //---------------------------------------------------------------------------------------------------------- Ligne rajoute

    import java.util.ArrayList;import java.util.List;import javax.xml.bind.annotation.*;

    @XmlAccessorType(XmlAccessType.FIELD) //------------------------------------------------------------ Element racine@XmlType(name = "", propOrder = {"forme"})@XmlRootElement(name = "Formes")public class Formes {

    @XmlElement(name = "Forme") protected List forme;

    public List getForme() { if (forme == null) { forme = new ArrayList(); } return this.forme; }

    @XmlAccessorType(XmlAccessType.FIELD) //----------------------------------------------------- Element Forme @XmlType(name = "", propOrder = {"centre","largeur"}) public static class Forme {

    protected Formes.Forme.Centre centre;

    @XmlSchemaType(name = "unsignedInt") protected Long largeur;

    @XmlAttribute(required = true) protected String type;

    public Formes.Forme.Centre getCentre() { return centre; }

    public void setCentre(Formes.Forme.Centre value) { this.centre = value; }

  • public void setCentre(Formes.Forme.Centre value) { this.centre = value; }

    public Long getLargeur() { return largeur; } public void setLargeur(Long value) { this.largeur = value; }

    public String getType() { return type; } public void setType(String value) { this.type = value; }

    @XmlAccessorType(XmlAccessType.FIELD) //--------------------------------------------------- Element Centre @XmlType(name = "") public static class Centre {

    @XmlAttribute(required = true) protected int x;

    @XmlAttribute(required = true) protected int y;

    public int getX() { return x; } public void setX(int value) { this.x = value; }

    public int getY() { return y; } public void setY(int value) { this.y = value; } } }}

    ObjectFactory.java (sans les commentaires)

    package jaxb; //---------------------------------------------------------------------------------------------------------- Ligne rajoute

    import javax.xml.bind.annotation.XmlRegistry;

    @XmlRegistrypublic class ObjectFactory {

    public ObjectFactory() {}

    public Formes.Forme createFormesForme() { return new Formes.Forme(); }

    public Formes createFormes() { return new Formes(); }

    public Formes.Forme.Centre createFormesFormeCentre() { return new Formes.Forme.Centre(); }}

    Utiliser l'API JAXB 2.0

    JAXB fournie une API qui permet l'excution d'effectuer les oprations de transformation d'un document XML en un graphe d'objets utilisant les classes gnres et vice et versa(unmashalling/marshalling) ainsi que des oprations de validation.

    1. L'objet principal pour les oprations de transformation est l'objet JAXBContext : il permet d'utiliser l'API JAXB. Pour obtenir une instance de cet objet, il suffit d'utiliser lamthode statique newInstance() en lui passant en argument le ou les paquetages contenant les classes gnres utiliser. Dans le cas ou plusieurs paquetages doivent treprciss, il faut les sparer par une virgule.

    JAXBContext contexte = JAXBContext.newInstance("jaxb");

    2. Une autre surdfinition de la mthode newInstance() attend en argument la classe qui encapsule la racine du document.

    Mapper un document XML des objets (unmarshal)

    L'API JAXB propose de transformer un document XML en un ensemble d'objets qui vont encapsuler les donnes et la hirarchie du document. Ces objets sont des instances des classesgnres partir du schma XML.

    1. La cration des objets ncessite la cration d'un objet de type JAXBContext en utilisant la mthode statique newInstance(), comme nous venons de le dcouvrir.

    2. 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 lamthode createUnmarshaller() de la classe JAXBContext.

    Unmarshaller mapperXMLObjet = contexte.createUnmarshaller();

    3. La mthode 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. Ellepossde de nombreuses surdfinitions utiliser en fonction des besoins.

    Formes formes = (Formes) mapperXMLObjet.unmarshal(new File("Formes.xml"));

    4. A partir de cet objet, il est possible d'obtenir et de modifier des donnes encapsules dans les diffrents objets crs partir des classes gnres et du contenu du document.Chacun de ces objets possdent des getter et des setter sur leur noeud direct.

    Exemple de mise en oeuvre au travers de l'application fentre

    Je vous propose de finaliser ces concepts au travers de l'application fentre qui trace les formes stockes dans le document XML, dont voici le rsultat :

  • Codage de l'application fentre

    package jaxb;

    import java.awt.*;import java.io.File;import javax.swing.*;import javax.xml.bind.*;

    public class Principal extends JFrame { private Trac dessins = new Trac();

    public Principal() { super("Trac de formes"); add(dessins); setSize(400, 300); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); }

    public static void main(String[] args) { new Principal(); }

    private class Trac extends JComponent { private Formes formes; public Trac() { try { JAXBContext contexte = JAXBContext.newInstance("jaxb"); Unmarshaller mapperXMLObjet = contexte.createUnmarshaller(); formes = (Formes) mapperXMLObjet.unmarshal(new File("Formes.xml")); } catch (JAXBException ex) { setTitle("Impossible de rcuprer le document XML"); } }

    @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D surface = (Graphics2D) g; surface.setStroke(new BasicStroke(5)); surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (formes!=null) for (Formes.Forme forme : formes.getForme()) { long largeurLong = forme.getLargeur(); int largeur = (int) largeurLong; int x = forme.getCentre().getX() - largeur/2; int y = forme.getCentre().getY() - largeur/2; String type = forme.getType(); if (type.equals("Carr")) surface.drawRect(x, y, largeur, largeur); else surface.drawOval(x, y, largeur, largeur); } } }}

    Crer un document XML partir d'objets

    JAXB permet de crer un document XML partir d'un graphe d'objets : cette opration est nomme marshalling. Une operation de mashalling est l'opration inverse de l'oprationd'unmarshalling.

    Ce graphe d'objets peut tre issu d'une opration de type unmarshalling (construction partir d'un document XML existant) ou issu d'une cration de toutes pices de l'ensembledes objets. Dans le premier cas cela correspond une modification du document et dans le second cas une cration de document.

    1. La cration des objets ncessite la cration d'un objet de type JAXBContext en utilisant la mthode statique newInstance(), comme prcdemment.

    2. Il faut ensuite instancier un objet de type Marshaller qui va permettre de transformer un ensemble d'objets en un document XML. Un telle instance est obtenue en utilisant lamthode createMarshaller() de la classe JAXBContext.

    3. La mthode marshal() de la classe Marshaller se charge de crer un document XML partir d'un graphe d'objets dont l'objet racine lui est fourni en paramtre. La mthodemarshal() possde plusieurs surdfinition qui permettent de prciser la forme du document XML gnr :

    un fichier (File),

  • un flux (OutputStream),

    un flux de caractre (Writer),

    un document DOM (Document),

    un gestionnaire d'vnement SAX (ContentHandler),

    un objet de type javax.xml.transform.SAXResult,

    un objet de type javax.xml.transform.DOMResult,

    un objet de type javax.xml.transform.StreamResult,

    un objet de type javax.xml.stream.XMLStreamWriter,

    ou un objet de type javax.xml.stream.XMLEventWriter.

    4. L'objet Mashaller possde des proprits qu'il est possible de valoriser en utilisant la mthode setProperty(). Les spcifications de JAXB proposent des proprits qui doivent treobligatoirement supportes par l'implmentation. Chaque implmentation est libre de proposer des proprits supplmentaires.

    JAXB_ENCODING : Permet de prciser le jeux de caractres d'encodage du document XML.

    JAXB_FORMATTED_OUTPUT : Boolen qui indique si le document XML doit tre format.

    Exemple : demander le formattage du document cr :

    Marshaller mapperObjetsXML = contexte.createMarshaller();mapperObjetsXML.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

    La cration d'un document XML partir d'objets peut se faire suivant deux approches qui seront traites dans les chapitres qui suivent :

    1. En utilisant les classes gnres partir d'un Schma XML.

    2. En utilisant des classes annotes sans tre oblig d'utiliser un Schma XML.

    Cration d'un document XML partir d'objets suivant un Schma XML

    Comme nous l'avons dcouvert dans les chapitres prcdents, une des classes gnres partir du schma se nomme ObjectFactory : c'est une fabrique d'objets pour les classes gnresqui encapsulent des donnes d'un document respectant le schma.

    Pour crer un document XML en utilisant ces classes, il faut suivre les tapes que nous avons voqu dans la fin du chapitre prcdent :

    1. La cration du document ncessite la cration d'un objet de type JAXBContext en utilisant la mthode statique newInstance().

    2. Il faut ensuite crer le graphe d'objets en utilisant la classe ObjectFactory pour instancier les diffrents objets et valoriser les donnes de ces objets en utilisant les setter.

    ObjectFactory fabrique = new ObjectFactory(); Formes formes = fabrique.createFormes();Formes.Forme forme = fabrique.createFormesForme();Formes.Forme.Centre centre = fabrique.createFormesFormeCentre();

    3. Il faut ensuite crer un objet de type Marshaller partir du contexte et appeler sa mthode marshall() pour gnrer le document.

    Exemple de mise en oeuvre au travers de l'application fentre

    Je vous propose de finaliser ces concepts au travers d'une application fentre qui trace les formes directement sur la zone principale de la fentre et qui peut stocker par la suite tous lesformes prsentes dans le document XML correspondant :

    Codage de l'application fentre

    package jaxb;

    import java.awt.*;import java.awt.event.*;import java.io.File;import javax.swing.*;import javax.xml.bind.*;

    public class Principal extends JFrame { private Trac dessins = new Trac(); private JRadioButton cercle = new JRadioButton("Cercle", true); private JRadioButton carr = new JRadioButton("Carr"); private JFormattedTextField largeur = new JFormattedTextField(50L); private ButtonGroup groupe = new ButtonGroup(); private JPanel boutons = new JPanel(); private JToolBar barre = new JToolBar();

  • public Principal() { super("Trac de formes"); add(barre, BorderLayout.NORTH); barre.add(new AbstractAction("Nouveau", new ImageIcon("nouveau.gif")) { public void actionPerformed(ActionEvent e) { dessins.effacer(); } }); barre.add(new AbstractAction("Enregistrer", new ImageIcon("enregistrer.gif")) { public void actionPerformed(ActionEvent e) { dessins.enregistrer(); } }); dessins.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (cercle.isSelected()) dessins.ajoutForme("Cercle", e.getX(), e.getY()); else dessins.ajoutForme("Carr", e.getX(), e.getY()); } }); add(dessins); largeur.setColumns(5); boutons.add(cercle); boutons.add(carr); boutons.add(largeur); groupe.add(cercle); groupe.add(carr); add(boutons, BorderLayout.SOUTH); setSize(400, 300); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); }

    public static void main(String[] args) { new Principal(); }

    private class Trac extends JComponent { private Formes formes; private Marshaller mapperObjetsXML; private ObjectFactory fabrique = new ObjectFactory(); public Trac() { try { JAXBContext contexte = JAXBContext.newInstance(Formes.class); mapperObjetsXML = contexte.createMarshaller(); mapperObjetsXML.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); formes = fabrique.createFormes(); } catch (JAXBException ex) { setTitle("Impossible de crer le document XML"); } }

    @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D surface = (Graphics2D) g; surface.setStroke(new BasicStroke(5)); surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (formes!=null) for (Formes.Forme forme : formes.getForme()) { long largeurLong = forme.getLargeur(); int largeur = (int) largeurLong; int x = forme.getCentre().getX() - largeur/2; int y = forme.getCentre().getY() - largeur/2; String type = forme.getType(); if (type.equals("Carr")) surface.drawRect(x, y, largeur, largeur); else surface.drawOval(x, y, largeur, largeur); } }

    public void effacer() { formes = fabrique.createFormes(); revalidate(); repaint(); }

    public void ajoutForme(String type, int x, int y) { Formes.Forme forme = fabrique.createFormesForme(); forme.setType(type); forme.setLargeur((Long) largeur.getValue()); Formes.Forme.Centre centre = fabrique.createFormesFormeCentre(); centre.setX(x); centre.setY(y); forme.setCentre(centre); formes.getForme().add(forme); repaint(); }

    private void enregistrer() { try { mapperObjetsXML.marshal(formes, new File("Formes.xml")); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } } }

    }

    Mapping XML/Objets en passant par les annotations

    JAXB permet de mapper un document XML vers une ou plusieurs classes annotes, ou inversement, sans tre oblig d'utiliser un schma XML. Dans ce cas, le dveloppeur a la charge

  • d'crire la ou les classes annotes requises.

    Dans nos dveloppement, il arrive trs souvent que nous manipulions un ensemble d'informations, de diffrentes natures, comme un systme de gestion de personnel ou encorecomme le logiciel de trac de formes. Ces informations sont toujours structures sous forme de classes, et derrire, nous manipulons les objets correspondants.

    Nous avons quelquefois besoin de pouvoir stocker ces informations dans un fichier afin de les retrouver par la suite. Se pose alors la question du format de stockage.Nous avons vu que le document XML est une bonne alternative puisqu'il est facile de le lire avec un simple diteur de texte.

    Dans ce contexte, il serait judicieux de pouvoir fabriquer ces documents XML directement par l'intermdiaire des classes dj existantes (mapping Objets/XML), sanspasser par un Schma XML (puisqu'encore aucun document n'existe). C'est dans ce cadre l que nous pouvons rajouter des annotations spcifiques directement sur lesclasses concernes.

    Il n'est donc plus ncessaire d'utiliser des classes gnres par le compilateur de schma mais dans ce cas, la ou les classes doivent tre cres manuellement en utilisant lesannotations adquates. La classe qui encapsule la racine du document doit tre annote avec l'annotation @XmlRootElement. Une exception de typejavax.xml.bind.MarshalException est leve par JAXB si la classe racine ne possde pas cette annotation.

    JAXB utilise des comportements par dfaut qui ne ncessite de la part du dveloppeur que de dfinir des comportements particuliers si la valeur par dfaut ne convient pas. Ainsi,nous pouvons limiter le nombre d'annotations requises.

    Communication entre le document XML et les objets correspondants

    Comme nous l'avons dcouvert dans les chapitres prcdents, le mapping entre un document XML et les objets correspondants, se feront par l'intermdiaires des classes JAXBContext,Marshaller et Unmarshaller.

    1. La cration ou la connexion avec un document XML ncessite la cration d'un objet de type JAXBContext en utilisant la mthode statique newInstance().

    2. Il faut ensuite crer un objet de type Marshaller partir du contexte et d'appeler sa mthode marshall() pour gnrer le document XML partir des objets dj crs.

    3. Ou bien crer un objet de type Unmarshaller partir du contexte et d'appeler sa mthode unmarshall() pour gnrer les objets correspondant au document XML.

    Annotation des classes

    La configuration de la transformation d'un document XML en objets Java est ralise grce l'utilisation d'annotations ddies dans les classes Java. De nombreuses annotations sontdfinies par JAXB 2.0. Toutes ces annotations sont dfinies dans le package javax.xml.bind.annotation.

    Annotation Description

    XmlAccessorOrder Contrler l'ordre des attributs et des proprits dans la classe.

    XmlAccessorType Contrler si l'attribut ou la proprit de la classe est srialis par dfaut.

    XmlAnyAttribute Convertir une proprit de la classe en un ensemble d'attributs de type jocker dans le document XML.

    XmlAnyElement Convertir une proprit de la classe en une description representant l'lment JAXB dans le document XML.

    XmlAttachmentRef Marquer un attribut ou une proprit de la classe comme une URI que fait rfrence une type MIME particulier.

    XmlAttribute Convertir une proprit de la classe en un attribut dans le document XML.

    XmlElement Convertir une proprit de la classe en un lment dans le document XML.

    XmlElementDecl Associer une fabrique un element XML.

    XmlElementRef Convertir une proprit de la classe en un lment dans le document XML qui est associ un nom de proprit particulier.

    XmlElementRefs Marquer une proprit de la classe qui fait rfrence aux classes qui possdente XmlElement ou JAXBElement.

    XmlElements Crer un conteneur pour de multiples annotations XmlElement, qui prcise ainsi le choix possible parmi celles qui sont proposes.

    XmlElementWrapper Crer un lment pre dans le document XML pour des collections d'lments.

    XmlEnum Convertir une numration en une reprsentation quivalente dans le document XML.

    XmlEnumValue Convertir un numrateur en une reprsentation quivalente dans le document XML.

    XmlID Convertir une proprit de la classe en un ID XML.

    XmlIDREF Convertir une proprit de la classe en un IDREF XML.

    XmlInlineBinaryData Encoder en base64 dans le document XML.

    XmlList Utilis pour convertir une proprit de la classe vers une liste de type simple.

    XmlMimeType Associer un type MIME qui contrle la reprsentation XML en rapport avec la proprit de la classe.

    XmlMixed Annoter une proprit de la classe qui peut supporter plusieurs types de valeur avec un contenu mixte.

    XmlNs Associer un prefix d'un espace de nommage une URI.

    XmlRegistry Marquer une classe comme possdant une ou des mthodes annotes avec XmlElementDecl.

    XmlRootElement Associer une classe ou une numration un element XML. Trs souvent utilis pour spcifier la racine du document XML.

    XmlSchema Associer un espace de nommage un paquetage.

    XmlSchemaType Associer un type Java ou une numeration un type dfini dans un schma.

    XmlSchemaTypes Conteneur pour plusieurs proprits annotes par XmlSchemaType.

    XmlTransient Marquer une entit pour qu'elle ne soit pas mappe dans le document XML.

    XmlType Convertir une classe ou une numration vers le type spcifi dans Shma XML correspondant.

    XmlValue Mapper une classe vers le type complexe dans le Schma XML ou vers le type simple suivant le cas.

  • Premier exemple de mise en oeuvre - pas d'attributs dans les balises

    Nous allons toute de suite laborer un premier exemple qui permet de faire du trac de formes, comme prcdemment, avec la possiblit de sauvegarder le trac ralis sur l'IHM dans undocument XML et de pouvoir ensuite le restituer loisir. Tout ceci se fait sans document XML pralable, et plus forte raison, sans Schma XML quivalent.

    Dans ce premier exemple, nous ne proprosons pas d'attributs dans les balises. Du coup, il devient ncessaire de prvoir des balises spcifiques pour les coordonnes. Remarquezau passage que notre document Formes, reprsent par l'lment racine peut aussi bien accueillir des lments que des lments , ce qui offre unestructure un petit peu plus complique que prcdemment.

    Mise en place du source relatif aux formes

    package jaxb;

    import java.awt.Graphics2D;import java.util.ArrayList;import javax.xml.bind.annotation.*;

    // Dfinition de l'lment racine du document et de ses sous-lments@XmlRootElementpublic class Formes { @XmlElements({ @XmlElement(name = "carr", type = Carr.class), @XmlElement(name = "cercle", type = Cercle.class) }) private ArrayList formes = new ArrayList();

    public ArrayList getFormes() { return formes; } public void ajoutForme(Forme forme) { formes.add(forme); } public void supprimerFormes() { formes.clear(); }}

    // hirarchie des classes reprsentant l'ensemble des formes possiblesabstract class Forme { protected int x, y; public Forme() {} public Forme(int x, int y) { this.x = x; this.y=y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } abstract void dessine(Graphics2D surface);}

    class Cercle extends Forme { private int rayon = 50; public Cercle() {} public Cercle(int x, int y, int rayon) { super(x, y); this.rayon = rayon; } public int getRayon() { return rayon; } public void setRayon(int rayon) { this.rayon = rayon; } @Override void dessine(Graphics2D surface) { surface.drawOval(x-rayon, y-rayon, 2*rayon, 2*rayon); }}

    class Carr extends Forme { private int ct = 100; public Carr() {} public Carr(int x, int y, int ct) { super(x, y); this.ct = ct; } public int getCt() { return ct; } public void setCt(int ct) { this.ct = ct; } @Override void dessine(Graphics2D surface) { surface.drawRect(x-ct/2, y-ct/2, ct, ct); }}

    Dans ce source, nous dcouvrons deux parties essentielles :

    1. La hirarchie des classes qui reprsente l'ensemble des formes, avec mme une classe de base abstraite. Ce sont ces classes que nous utilisons directement dans l'IHM.Remarquez, qu'elles ne possdent aucune annotation particulire.

    2. La premire partie du code est cette fois-ci plus spcifique l'laboration du document XML. Dans ce cadre l, une classe Formes est spcialement cre pour reprsenterl'lment racine du document qui est spcifi au travers de l'annotation @XmlRootElement.

    3. Cette classe Formes possde un seul attribut : formes qui reprsente l'ensemble des formes susseptibles d'tre enregistres. Comme il existe plusieurs formes possibles, nousutilisons une annotation particulire, juste au-dessus de l'attribut, qui va servir prciser quels sont les lments autoriss intgrer l'ensemble des formes. Il s'agit del'annotation @XmlElements l'intrieur de laquelle nous allons positionner des annotations de type @XmlElement qui vont permettre de choisir prcisment la classe prendreen compte avec le nom de la balise associe. Ainsi, lorsque nous placerons une forme, le systme proposera la balise correspondante parmi celles qui font partie de l'ensembledfini par l'annotation @XmlElements.

    L'attribut name de l'annotation @XmlElement permet d'indiquer le nom de la balise dans le document XML.

    L'attribut type de l'annotation @XmlElement permet d'indiquer le nom de la classe associe.

    4. Et c'est tout ... Finalement, nous utilisons trs trs peu d'annotations.

  • Codage de l'application principale

    package jaxb;

    import java.awt.*;import java.awt.event.*;import java.io.File;import javax.swing.*;import javax.xml.bind.*;import jaxb.Formes.*;

    public class Principal extends JFrame { private Trac dessins = new Trac(); private JRadioButton cercle = new JRadioButton("Cercle", true); private JRadioButton carr = new JRadioButton("Carr"); private JFormattedTextField largeur = new JFormattedTextField(50); private ButtonGroup groupe = new ButtonGroup(); private JPanel boutons = new JPanel(); private JToolBar barre = new JToolBar();

    public Principal() { super("Trac de formes"); add(barre, BorderLayout.NORTH); barre.add(new AbstractAction("Nouveau", new ImageIcon("nouveau.gif")) { public void actionPerformed(ActionEvent e) { dessins.effacer(); } }); barre.add(new AbstractAction("Ouvrir", new ImageIcon("ouvrir.gif")) { public void actionPerformed(ActionEvent e) { dessins.ouvrir(); } }); barre.add(new AbstractAction("Enregistrer", new ImageIcon("enregistrer.gif")) { public void actionPerformed(ActionEvent e) { dessins.enregistrer(); } }); dessins.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { int larg = (Integer)largeur.getValue(); if (cercle.isSelected()) dessins.ajoutForme(new Cercle(e.getX(), e.getY(), larg/2)); else dessins.ajoutForme(new Carr(e.getX(), e.getY(), larg)); } }); add(dessins); largeur.setColumns(3); boutons.add(cercle); boutons.add(carr); boutons.add(largeur); groupe.add(cercle); groupe.add(carr); add(boutons, BorderLayout.SOUTH); setSize(400, 300); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); }

    public static void main(String[] args) { new Principal(); }

    private class Trac extends JComponent { private Formes formes = new Formes(); private Marshaller mapperObjetsXML; private Unmarshaller mapperXMLObjets; public Trac() { try { JAXBContext contexte = JAXBContext.newInstance(Formes.class); mapperObjetsXML = contexte.createMarshaller(); mapperObjetsXML.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); mapperXMLObjets = contexte.createUnmarshaller(); } catch (JAXBException ex) { setTitle("Impossible de crer le document XML"); } }

    @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D surface = (Graphics2D) g; surface.setStroke(new BasicStroke(5)); surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (formes!=null) for (Forme forme : formes.getFormes()) forme.dessine(surface); }

    public void effacer() { formes.supprimerFormes(); revalidate(); repaint(); }

    public void ajoutForme(Forme forme) { formes.ajoutForme(forme); repaint(); }

    private void enregistrer() { try { mapperObjetsXML.marshal(formes, new File("Formes.xml")); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } }

  • private void ouvrir() { try { formes = (Formes) mapperXMLObjets.unmarshal(new File("Formes.xml")); repaint(); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } } }}

    Vous remarquez ici, par rapport aux chapitres prcdents, que la gestion des formes est beaucoup plus simple, puisqu'il s'agit de classes des plus normales sans annotationsparticulires. Le fait d'avoir d'ailleurs une classe abstraite commune permet de simplifier encore plus le problme.

    L'utilisation des annotations sans passer par une Schma XML me parat finalement plus facile mettre en oeuvre et surtout plus intuitif. L'intrt du Schma XML est surtoutintressant lorsque nous devons faire une application qui tient compte de documents XML dj existants.

    Quelques considrations techniques sur certaines annotations

    Le tableau ci-dessous reprend quelques-unes des annotations pour bien prciser leur particularit et leur utilit.

    Annotation Considrations

    XmlRootElement Peut tre utilise sur une classe pour prciser que cette classe sera l'lment racine du document XML. Chaque attribut de la classe devient ainsi unlment fils dans le document XML. L'attribut namespace de l'annotation @XmlRootElement permet de prciser l'espace de nommage.

    Codage de la classe Personne qui va servir de rfrence

    import java.util.Date; import javax.xml.bind.annotation.*; @XmlRootElement public class Personne { private String nom; private String prenom; private int taille; private Date dateNaissance; public Personne() { } public Personne(String nom, String prenom, int taille, Date dateNaissance) { super(); this.nom = nom; this.prenom = prenom; this.taille = taille; this.dateNaissance = dateNaissance; } public Date getDateNaissance() { return dateNaissance; } public void setDateNaissance(Date dateNaissance) { this.dateNaissance = dateNaissance; } 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; } }

    Rsultat

    REMY Emmanuel 171 2007-01-16T17:03:31.213+01:00

    XmlTransient Permet d'ignorer une proprit/entit dans la mapping entre l'objet et l'lment XML correspondant :

    Exemple

    import java.util.Date; import javax.xml.bind.annotation.*; @XmlRootElement public class Personne { ... @XmlTransient

  • public String getNom() { return nom; } ...

    }

    Rsultat

    Emmanuel 171 2007-01-16T17:03:31.213+01:00

    XmlAttribute Permet de mapper une proprit sous la forme d'un attribut et fournir des prcisions sur la configuration de cet attribut

    Exemple

    import java.util.Date; import javax.xml.bind.annotation.*; @XmlRootElement public class Personne { ... @XmlAttribute public String getNom() { return nom; } ...}

    Rsultat

    Emmanuel 171 2007-01-16T17:03:31.213+01:00

    XmlElementWrapper Pour les collections, il est possible d'utiliser l'annotation @XmlElementWrapper pour dfinir un lement pre qui encapsule les occurrences de lacollection et d'utiliser l'annotation @XmlElement pour prciser le nom de chaque lment de la collection.

    Exemple

    import java.util.Date; import javax.xml.bind.annotation.*; @XmlRootElement public class Personne { private String nom; private String prenom; private int taille; private Date dateNaissance; @XmlElementWrapper(name = "Residence") @XmlElement(name = "Adresse") protected List adresses = new ArrayList(); ... }

    class Adresse { private String rue; private int codePostal; private String ville; private String pays;...}

    Rsultat

    REMY Emmanuel 171 2007-01-16T17:03:31.213+01:00 Nom de la rue 78895 Une ville France

    XmlType Il est possible de configurer l'ordre des lments au travers de cette annotation

    Exemple

    import java.util.Date; import javax.xml.bind.annotation.*; @XmlRootElement @XmlType(propOrder = {"dateNaissance", "adresses", "nom", "prenom", "taille"}) public class Personne { private String nom; private String prenom; private int taille; private Date dateNaissance;

    @XmlElementWrapper(name = "Residence") @XmlElement(name = "Adresse")

  • protected List adresses = new ArrayList(); ... }

    class Adresse { private String rue; private int codePostal; private String ville; private String pays;...

    }

    Rsultat

    2007-01-16T17:03:31.213+01:00 Nom de la rue 78895 Une ville France REMY Emmanuel 171

    XmlJavaTypeAdapter Il est possible de dfinir des classes de type Adapter qui permettent de personnaliser la faon dont un objet est serialis/desrialis dans le documentXML. Ces classes Adapter hritent de la classe javax.xml.bind.annotation.adapters.XmlAdapter. Il suffit de redfinir les mthodes marshal() et unmashal()afin de permettre un formatage de l'information adapt au visuel que nous dsirons faire apparatre ct document XML. Ces mthodes serontautomatiquement utilises l'excution par l'API JAXB lors des transformations. L'annotation @XmlJavaTypeAdapter permet de prciser la classe de typeAdapter qui sera utiliser plutt que d'utiliser la conversion par dfaut

    Exemple

    import java.util.Date; import java.text.*; import javax.xml.bind.annotation.*;import javax.xml.bind.annotation.adapters.*; @XmlRootElement @XmlType(propOrder = {"dateNaissance", "adresses", "nom", "prenom", "taille"}) public class Personne { private String nom; private String prenom; private int taille; @XmlJavaTypeAdapter(DateAdapter.class) private Date dateNaissance; @XmlElementWrapper(name = "Residence") @XmlElement(name = "Adresse") protected List adresses = new ArrayList(); ... }

    class Adresse { private String rue; private int codePostal; private String ville; private String pays;...}

    class DateAdapter extends XmlAdapter { private DateFormat miseEnForme = DateFormat.getDateInstance(DateFormat.LONG);

    public Date unmarshal(String date) throws Exception { return miseEnForme.parse(date); }

    public String marshal(Date date) throws Exception { return miseEnForme.format(date); } }

    Rsultat

    1 octobre 1959 Nom de la rue 78895 Une ville France REMY Emmanuel 171

    Deuxime exemple de mise en oeuvre - Mise en place d'attributs dans les balises XML

    Nous allons reprendre l'application prcdente qui permet de sauvegarder, et donc de restituer un ensemble de formes, dans un document XML. Ce document XML est lgrementdiffrent que le prcdent. Pour chacune des formes, nous envisageons, cette fois-ci, de prendre une nouvelle balise nomme l'intrieur de laquelle nous stipulons lescoordonnes du centre de la forme.

    Cette fois-ci nous devons proposer des attributs, respectivement x et y, qui vont reprsenter les coordonnes dela balise .

  • Mise en place du source relatif aux formes

    package jaxb;

    import java.awt.Graphics2D;import java.util.ArrayList;import javax.xml.bind.annotation.*;

    // Dfinition de l'lment racine du document et de ses sous-lments@XmlRootElementpublic class Formes { @XmlElements({ @XmlElement(name = "carr", type = Carr.class), @XmlElement(name = "cercle", type = Cercle.class) }) private ArrayList formes = new ArrayList();

    public ArrayList getFormes() { return formes; } public void ajoutForme(Forme forme) { formes.add(forme); } public void supprimerFormes() { formes.clear(); }}

    // La classe Forme est modifie pour accueillir un centre la place des coordonnes x et yabstract class Forme { protected Centre centre; public Forme() { centre = new Centre(); } public Forme(int x, int y) { centre = new Centre(x, y); } public Centre getCentre() { return centre; } public void setCentre(Centre centre) { this.centre = centre; } abstract void dessine(Graphics2D surface);}

    // Nouvel lment reprsenant le qui possde deux attributs x et yclass Centre { @XmlAttribute private int y; @XmlAttribute private int x;

    public Centre() {} public Centre(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } }

    class Cercle extends Forme { private int rayon = 50; public Cercle() {} public Cercle(int x, int y, int rayon) { super(x, y); this.rayon = rayon; } public int getRayon() { return rayon; } public void setRayon(int rayon) { this.rayon = rayon; } @Override void dessine(Graphics2D surface) { int x = centre.getX(); int y = centre.getY(); surface.drawOval(x-rayon, y-rayon, 2*rayon, 2*rayon); }}

    class Carr extends Forme { private int ct = 100; public Carr() {} public Carr(int x, int y, int ct) { super(x, y); this.ct = ct; } public int getCt() { return ct; } public void setCt(int ct) { this.ct = ct; } @Override void dessine(Graphics2D surface) { int x = centre.getX(); int y = centre.getY(); surface.drawRect(x-ct/2, y-ct/2, ct, ct); }}

    Dans ce source, nous pouvons faire un certain nombre de remarques :

    1. La plus grosse partie du code n'est pas modifie.

    2. Nous devons mettre en oeuvre une classe Centre qui, ds lors, possde les coordonnes des formes souhaites. Les coordonnes deviennent alors des attributs XML de cetteclasse Centre.

    3. Dans la classe Forme, nous proposons un nouvel attribut centre, de type Centre, qui remplace les attributs x et y. Les constructeurs doivent prendre en compte la cration de cesdiffrents centres.

    4. Il faut revoir galement les mthodes redfinies dessine() puisque nous ne pouvons plus accder directement aux coordonnes.

  • 5. Encore une fois, malgrs un changement notable sur le document XML, nous utilisons trs peu d'annotations.

    Rpertoire tlphonique avec une MAP

    Cette fois-ci, nous changeons de sujet. Nous proposons une application qui permet de stocker un petit rpertoire tlphonique de portable associ juste quelques prnoms connus. Cerpertoire devra toutefois tre dans l'ordre alphabtique des prnoms.

    Source du rpertoire tlphonique

    package carte;

    import java.awt.*;import java.awt.event.ActionEvent;import java.io.File;import java.text.ParseException;import javax.swing.*;import java.util.*;import javax.swing.text.MaskFormatter;import javax.xml.bind.*;import javax.xml.bind.annotation.*;

    public class GestionRpertoire extends JFrame { private JTextField prnom = new JTextField("Nouveau prnom", 18); private JFormattedTextField tlphone; private JPanel panneau = new JPanel(); private JToolBar barre = new JToolBar(); private Marshaller mapperObjetsXML; private Unmarshaller mapperXMLObjets; private Rpertoire rpertoire = new Rpertoire(); private JComboBox liste = new JComboBox();

    public GestionRpertoire() throws ParseException { super("Rpertoire tlphonique"); documentXML(); liste.setForeground(Color.RED); tlphone = new JFormattedTextField(new MaskFormatter("##-##-##-##-##")); tlphone.setValue("06-00-00-00-00"); barre.add(new AbstractAction("Ajout") { public void actionPerformed(ActionEvent e) { rpertoire.ajout(prnom.getText(), (String) tlphone.getValue()); rpertoire.miseAJour(liste); } }); barre.add(new AbstractAction("Suppression") { public void actionPerformed(ActionEvent e) { rpertoire.suppression(prnom.getText()); rpertoire.miseAJour(liste); } }); barre.add(new AbstractAction("Ouvrir", new ImageIcon("ouvrir.gif")) { public void actionPerformed(ActionEvent e) { try { rpertoire = (Rpertoire) mapperXMLObjets.unmarshal(new File("Tlphones.xml")); rpertoire.miseAJour(liste); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } } }); barre.add(new AbstractAction("Enregistrer", new ImageIcon("enregistrer.gif")) { public void actionPerformed(ActionEvent e) { try { mapperObjetsXML.marshal(rpertoire, new File("Tlphones.xml")); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } } }); add(barre, BorderLayout.NORTH); panneau.add(new JLabel("Prnom : ")); panneau.add(prnom); panneau.add(new JLabel("Tlphone : ")); panneau.add(tlphone); add(panneau); add(liste, BorderLayout.SOUTH); pack(); setLocationRelativeTo(null); setResizable(false); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); }

    private void documentXML() { try { JAXBContext contexte = JAXBContext.newInstance(Rpertoire.class); mapperObjetsXML = contexte.createMarshaller();

  • mapperObjetsXML.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); mapperXMLObjets = contexte.createUnmarshaller(); } catch (JAXBException ex) { setTitle("Impossible de crer le document XML"); } } public static void main(String[] args) throws ParseException { new GestionRpertoire(); }}

    @XmlRootElementclass Rpertoire { private TreeMap rpertoire = new TreeMap();

    public TreeMap getRpertoire() { return rpertoire; } public void setRpertoire(TreeMap rpertoire) { this.rpertoire = rpertoire; }

    public void ajout(String prnom, String numro) { rpertoire.put(prnom, numro); } public void suppression(String prnom) { rpertoire.remove(prnom); } public void miseAJour(JComboBox liste) { liste.removeAllItems(); for (Map.Entry lment : rpertoire.entrySet()) liste.addItem(lment); }}

    Faisons un certain nombre de remarques :

    1. La classe utilise pour stocker l'ensemble des numros est la classe TreeMap qui permet de grer dans l'ordre ce que nous appelons des cartes.

    2. Nous plaons juste une annotation @XmlRootElement qui permet de grer l'ensemble des numros au travers de ce Map.

    3. Tout ce fait automatiquement.

    4. L'inconvnient toutefois, c'est que le nom des balises, dans le document XML, est alors impos. Nous trouvons donc des intituls correspondant la terminologie utilise parl'interface Map, c'est--dire : , et .

    5. Il sera ventuellement ncessaire de passer par une classe de type Adapter pour contrler le nom des balises du document XML.

    Rpertoire tlphonique avec une MAP et une classe d'adaptation pour le document XML

    Nous reprenons le mme sujet que prcdemment. L'objectif ici est de proposer une meilleure mise en forme du document XML pour une lecture plus adapte la situation.

    Partie du code sur la mise en forme du document XML uniquement

    ...

    @XmlRootElementclass Rpertoire { @XmlElement(name="tlphones") @XmlJavaTypeAdapter(MapAdapter.class) private TreeMap rpertoire = new TreeMap();

    public TreeMap getRpertoire() { return rpertoire; } public void ajout(String prnom, String numro) { rpertoire.put(prnom, numro); } public void suppression(String prnom) { rpertoire.remove(prnom); } public void miseAJour(JComboBox liste) { liste.removeAllItems(); for (Map.Entry lment : rpertoire.entrySet()) liste.addItem(lment); }}

    class MapAdapter extends XmlAdapter { @Override public TreeMap unmarshal(Tlphones tlphones) throws Exception { TreeMap cartes = new TreeMap(); for (Tlphone tlphone : tlphones.getTlphones()) cartes.put(tlphone.getPrnom(), tlphone.getNumro()); return cartes; } @Override public Tlphones marshal(TreeMap valeurs) throws Exception { Tlphones tlphones = new Tlphones(); for (Map.Entry carte : valeurs.entrySet()) tlphones.getTlphones().add(new Tlphone(carte.getKey(), carte.getValue())); return tlphones; }}

    class Tlphones { @XmlElement(name="tlphone") private ArrayList tlphones = new ArrayList(); public ArrayList getTlphones() { return tlphones; }}

    class Tlphone { @XmlAttribute private String numro; @XmlAttribute private String prnom;

  • public String getNumro() { return numro; } public String getPrnom() { return prnom; }

    public Tlphone(String prnom, String numro) { this.prnom = prnom; this.numro = numro; }

    public Tlphone() {}}

    Faisons un certain nombre de remarques :

    1. Il n'existe pas d'annotation spcifiques un conteneur de type Map. Nous devons donc tout construire pour avoir un document XML suivant notre souhait.

    2. Dans notre document XML, pour nommer un lment , nous devons utiliser spcifiquement l'annotation @XmlElement. Or, cette annotation ne se place qu'audessus d'une proprit de classe. La seule solution consiste donc crer une classe conteneur qui possde alors une liste d'lments. Ainsi chaque lment sera bien nomm, si le choix de l'attribut de la classe porte le mme nom o si nous spcifions le nom au travers de l'attribut name de l'annotation @XmlElement.

    3. Pour avoir des attributs sur cette balise , nous devons crer galement une classe dont chacune des proprits aura comme annotation @XmlAttribute. Ici aussi, lesattributs d'une balise correspondent toujours aux attributs d'une classe. La cration de cette classe devient donc obligatoire. Finalement la liste prcdente sera une liste de cetteclasse.

    4. Pour finir, il faut faire le lien entre la Map (liaison avec le programme principal) et la liste (liaison avec le document UML). La seule solution est de proposer une classe Adapterqui fait le marshalling et l'unmarshalling de faon adquat.

    Rpertoire tlphonique pouvant intgrer plusieurs tlphones

    Nous reprenons de nouveau la mme application. Chaque utilisateur peut cette fois-ci avoir plusieurs tlphones : le mobile, le tlphone du domicile ou le tlphone du travail.

    Source complet

    package carte;

    import java.awt.*;import java.awt.event.ActionEvent;import java.io.File;import java.text.ParseException;import javax.swing.*;import java.util.*;import javax.swing.text.MaskFormatter;import javax.xml.bind.*;import javax.xml.bind.annotation.*;import javax.xml.bind.annotation.adapters.*;

    public class GestionRpertoire extends JFrame { private JTextField prnom = new JTextField("Nouveau prnom", 18); private JFormattedTextField tlphone; private JPanel panneau = new JPanel(); private JToolBar barre = new JToolBar(); private Marshaller mapperObjetsXML; private Unmarshaller mapperXMLObjets; private Rpertoire rpertoire = new Rpertoire(); private JComboBox typeTlphone = new JComboBox(TypeTlphone.values()); private JComboBox liste = new JComboBox();

    public GestionRpertoire() throws ParseException { super("Rpertoire tlphonique"); documentXML(); liste.setForeground(Color.RED); tlphone = new JFormattedTextField(new MaskFormatter("##-##-##-##-##")); tlphone.setValue("06-00-00-00-00"); barre.add(new AbstractAction("Ajout") { public void actionPerformed(ActionEvent e) { rpertoire.ajout(prnom.getText(), typeTlphone.getSelectedItem(), (String) tlphone.getValue()); rpertoire.miseAJour(liste); } }); barre.add(new AbstractAction("Suppression") { public void actionPerformed(ActionEvent e) { rpertoire.suppression(prnom.getText()); rpertoire.miseAJour(liste); } }); barre.add(new AbstractAction("Ouvrir", new ImageIcon("ouvrir.gif")) { public void actionPerformed(ActionEvent e) { try { rpertoire = (Rpertoire) mapperXMLObjets.unmarshal(new File("Tlphones.xml")); rpertoire.miseAJour(liste); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } } }); barre.add(new AbstractAction("Enregistrer", new ImageIcon("enregistrer.gif")) {

  • public void actionPerformed(ActionEvent e) { try { mapperObjetsXML.marshal(rpertoire, new File("Tlphones.xml")); } catch (JAXBException ex) { setTitle("Impossible d'enregistrer le document XML"); } } }); add(barre, BorderLayout.NORTH); panneau.add(new JLabel("Prnom : ")); panneau.add(prnom); panneau.add(new JLabel("Tlphone : ")); panneau.add(typeTlphone); panneau.add(tlphone); add(panneau); add(liste, BorderLayout.SOUTH); pack(); setLocationRelativeTo(null); setResizable(false); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); }

    private void documentXML() { try { JAXBContext contexte = JAXBContext.newInstance(Rpertoire.class); mapperObjetsXML = contexte.createMarshaller(); mapperObjetsXML.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); mapperXMLObjets = contexte.createUnmarshaller(); } catch (JAXBException ex) { setTitle("Impossible de crer le document XML"); } }

    public static void main(String[] args) throws ParseException { new GestionRpertoire(); }}

    enum TypeTlphone {Mobile, Domicile, Travail};

    @XmlRootElementclass Rpertoire { @XmlElement(name="tlphones") @XmlJavaTypeAdapter(MapAdapter.class) private TreeMap rpertoire = new TreeMap();

    public TreeMap getRpertoire() { return rpertoire; } public void suppression(String prnom) { rpertoire.remove(prnom); }

    public void ajout(String prnom, Object type, String numro) { EnumMap tlphones; if (rpertoire.containsKey(prnom)) { tlphones = rpertoire.get(prnom); tlphones.put((TypeTlphone)type, numro); } else { tlphones = new EnumMap(TypeTlphone.class); tlphones.put((TypeTlphone)type, numro); rpertoire.put(prnom, tlphones); } }

    public void miseAJour(JComboBox liste) { liste.removeAllItems(); for (Map.Entry carte : rpertoire.entrySet()) liste.addItem(carte); }}

    class MapAdapter extends XmlAdapter { @Override public TreeMap unmarshal(Tlphones tlphones) throws Exception { TreeMap cartes = new TreeMap(); for (Tlphone tlphone : tlphones.getTlphones()) { EnumMap liste= new EnumMap(TypeTlphone.class); for (NumroParType npt : tlphone.getTlphone()) liste.put(npt.getType(), npt.getNumro()); cartes.put(tlphone.getPrnom(), liste); } return cartes; } @Override public Tlphones marshal(TreeMap valeurs) throws Exception { Tlphones tlphones = new Tlphones(); for (Map.Entry carte : valeurs.entrySet()) { Tlphone personne = new Tlphone(carte.getKey()); for (Map.Entry tlphone : carte.getValue().entrySet()) personne.ajoutTlphone(tlphone.getKey(), tlphone.getValue()); tlphones.getTlphones().add(personne); } return tlphones; }}

    class Tlphones { @XmlElement(name="personne") private ArrayList tlphones = new ArrayList(); public ArrayList getTlphones() { return tlphones; }}

    class Tlphone { @XmlAttribute private String prnom; @XmlElement private ArrayList tlphone = new ArrayList();

    public Tlphone(String prnom) { this.prnom = prnom; } public Tlphone() {}

  • public String getPrnom() { return prnom; }

    public ArrayList getTlphone() { return tlphone; }

    public void ajoutTlphone(TypeTlphone type, String numro) { tlphone.add(new NumroParType(type, numro)); }}

    class NumroParType { @XmlAttribute private String numro; @XmlAttribute private TypeTlphone type;

    public NumroParType() {} public NumroParType(TypeTlphone type, String numro) { this.type = type; this.numro = numro; }

    public String getNumro() { return numro; } public TypeTlphone getType() { return type; }}

    Il existe une annotation @XmlEnum, mais vous remarquez qu'il n'a pas t ncessaire de la mettre en oeuvre. JAXB se dbrouille trs bien sans et propose les numrateurs sousforme de chanes de caractres, ceci automatiquement.

    Gnrer un schma partir de classes compiles

    L'outil schemagen fourni avec l'implmentation par dfaut permet de gnrer un schma XML partir de classes annotes compiles.

    Exemple d'application qui va servir de base pour la cration d'un schma XML

    Nous allons reprendre l'application du trac de formes qui permet de sauvegarder, et donc de restituer un ensemble de formes, dans un document XML.

    Cette fois-ci nous devons proposer des attributs, respectivement x et y, qui vont reprsenter les coordonnes dela balise .

    Mise en place du source relatif aux formes

    package jaxb;

    import java.awt.Graphics2D;import java.util.ArrayList;import javax.xml.bind.annotation.*;

    // Dfinition de l'lment racine du document et de ses sous-lments@XmlRootElementpublic class Formes { @XmlElements({ @XmlElement(name = "carr", type = Carr.class), @XmlElement(name = "cercle", type = Cercle.class) }) private ArrayList formes = new ArrayList();

    public ArrayList getFormes() { return formes; } public void ajoutForme(Forme forme) { formes.add(forme); } public void supprimerFormes() { formes.clear(); }}

    // La classe Forme est modifie pour accueillir un centre la place des coordonnes x et yabstract class Forme { protected Centre centre; public Forme() { centre = new Centre(); } public Forme(int x, int y) { centre = new Centre(x, y); } public Centre getCentre() { return centre; } public void setCentre(Centre centre) { this.centre = centre; } abstract void dessine(Graphics2D surface);}

    // Nouvel lment reprsenant le qui possde deux attributs x et yclass Centre { @XmlAttribute private int y; @XmlAttribute private int x;

    public Centre() {} public Centre(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; }

  • }class Cercle extends Forme { private int rayon = 50; public Cercle() {} public Cercle(int x, int y, int rayon) { super(x, y); this.rayon = rayon; } public int getRayon() { return rayon; } public void setRayon(int rayon) { this.rayon = rayon; } @Override void dessine(Graphics2D surface) { int x = centre.getX(); int y = centre.getY(); surface.drawOval(x-rayon, y-rayon, 2*rayon, 2*rayon); }}

    class Carr extends Forme { private int ct = 100; public Carr() {} public Carr(int x, int y, int ct) { super(x, y); this.ct = ct; } public int getCt() { return ct; } public void setCt(int ct) { this.ct = ct; } @Override void dessine(Graphics2D surface) { int x = centre.getX(); int y = centre.getY(); surface.drawRect(x-ct/2, y-ct/2, ct, ct); }}

    Utilisation de l'utilitaire schemagen

    Schema1.xsd