xjc
. On peut utiliser le même script Ant que pour la génération du schéma. Il suffit de lui ajouter les éléments suivants.
Exemple 22. Script Ant pour
xjc
<!-- définition de la tâche xjc, à ajouter à la suite de la définition de schemagen --> <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask"> <classpath refid="classpath"/> </taskdef> <target name="generate-classes"> <xjc destdir="src" package="org.paumard.model.generated" schema="marin.xsd"/> </target>
Exemple 23. Schéma de départ pour
xjc
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xs:schema version="1.0" xmlns:ns1="http://www.paumard.org/cours-jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="bateau"> <xs:sequence> <xs:element name="nom" type="xs:string" minOccurs="0"/> <xs:element name="equipage" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element name="equipage" type="marin" minOccurs="0" maxOccurs="10"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:long" use="required"/> </xs:complexType> <xs:complexType name="marin"> <xs:sequence> <xs:element name="nom" type="xs:string"/> <xs:element name="prenom" type="xs:string" minOccurs="0"/> <xs:element name="grade" type="grade" minOccurs="0"/> <xs:element name="age" type="xs:long"/> </xs:sequence> <xs:attribute name="id" type="xs:long" use="required"/> </xs:complexType> <xs:simpleType name="grade"> <xs:restriction base="xs:string"> <xs:enumeration value="MATELOT"/> <xs:enumeration value="BOSCO"/> <xs:enumeration value="PACHA"/> <xs:enumeration value="CUISINIER"/> </xs:restriction> </xs:simpleType> </xs:schema>
xjc
nous génère trois classes pour notre modèle :
Marin
,
Bateau
et
Grade
. Il en génère de plus une quatrième,
ObjectFactory
, qui est une classe fabrique pour la création des objets de ce modèle.
Examinons une version simplifiée des trois classes de notre modèle.
Exemple 24. Classes générées par
xjc
// // énumération Grade @XmlType(name = "grade") @XmlEnum public enum Grade { MATELOT, BOSCO, PACHA, CUISINIER; // reste de l'énumération } // // classe Bateau // @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "bateau", propOrder = {"nom", "equipage"}) public class Bateau { protected String nom; protected Bateau.Equipage equipage; @XmlAttribute(required = true) protected long id; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"equipage"}) public static class Equipage { protected List<Marin> equipage; // reste de la classe membre Equipage } // reste de la classe Bateau } // // classe Marin // @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "marin", propOrder = {"nom", "prenom", "grade", "age"}) public class Marin { @XmlElement(required = true) protected String nom; protected String prenom; protected Grade grade; protected long age; @XmlAttribute(required = true) protected long id; // reste de la classe Marin }
Grade
. Bien sûr, si l'on a utilisé des annotations
@EnumValue
pour remplacer les noms de grades par des entiers, cette énumération ne sera pas générée, et le champ
grade
sera un
Integer
dans la classe
Marin
.
La classe
Marin
générée est conforme à ce que l'on pourrait attendre. On remarque simplement que les champs de cette classe sont
protected
plutôt que
private
. On constate aussi la génération de l'annotation
@XmlType
, qui impose l'ordre des champs dans le document XML. Cela est dû au fait que les champs sont spécifiés dans un élément
sequence
plutôt que
all
, comme nous l'avions déjà remarqué.
La classe
Bateau
nous réserve un peu plus de surprises, notamment la façon dont le champ
equipage
a été traité. Nous avons utilisé une annotation
@XmlElementWrapper
sur le champ
equipage
de notre classe
Bateau
originelle, afin de regrouper les marins de notre équipage dans un sous-élément
equipage
. Bien sûr,
xjc
ne dispose d'aucune information pour reconstituer cette annotation, et il crée un champ
equipage
, de type
Bateau.Equipage
, qui encapsule la liste de marins
equipage
.
Notons également que la contrainte que nous avons posée dans le schéma sur l'élément
equipage
, et qui empêche son cardinal d'être plus grand que 10 n'a pas été prise en compte dans la génération de la classe
Bateau
.
Au final, on se rend compte que la génération des classes Java est moins précise, et probablement moins exploitable que celle du schéma.
xjc
:
ObjectFactory
. Cette classe est une classe fabrique, qui expose autant de méthodes que nous avons de classes générées. Cette classe est censée être utilisée de la façon suivante.
Exemple 25. Utilisation de
ObjectFactory
public static void main(String... args) { // création d'une instance d'ObjectFactory ObjectFactory factory = new ObjectFactory() ; // pattern de création d'un marin Marin marin = factory.createMarin() ; // pattern de création d'un bateau Bateau bateau = factory.createBateau() ; // pattern d'ajout d'un marin à l'équipage // 1) création d'un equipage Bateau.Equipage equipage = factory.createBateauEquipage() ; // 2) création d'un bateau Bateau bateau = factory.createBateau() ; // 3) initialisation du champ equipage de bateau bateau.setEquipage(equipage) ; // 4) ajout d'un marin à cet équipage bateau.getEquipage().getEquipage().add(marin) ; }
@Path
@Produces
et
@Consumes
@Provider
MessageBodyReader
et
MessageBodyWriter