schemagen
, et peut s'utiliser au travers d'une tâche Ant, ou d'un plugin Maven.
Écrivons un script Ant simple permettant d'utiliser le générateur de schéma.
Exemple 16. Script Ant pour
schemagen
<?xml version="1.0" encoding="UTF-8"?> <project name="generate-schema" default="generate-schema" basedir="."> <property name="jaxb.home" value="D:/java/JAXB-2.1/jaxb-ri-20081030"/> <!-- définition d’un classpath sur la distribution --> <path id="classpath"> <fileset dir="${jaxb.home}" includes="lib/*.jar" /> </path> <!-- définition d’une tâche Ant schemagen --> <taskdef name="schemagen" classname="com.sun.tools.jxc.SchemaGenTask"> <classpath refid="classpath"/> </taskdef> <!-- écriture de la cible Ant --> <target name="generate-schema"> <!-- src et destdit indiquent l'endroit où se trouvent les fichiers source et le répertoire où les fichiers XSD vont être créés --> <schemagen srcdir="../src" destdir="../schemas"> <!-- on peut fixer le nom du fichier XSD, ainsi que l'espace de noms --> <schema file="marin.xsd" namespace="http://www.paumard.org/cours-jaxb"/> <!-- on peut exclure des packages--> <exclude name="**/test/**"/> <exclude name="**/main/**"/> </schemagen> </target> </project>
jaxb.home
. Cette propriété référence le répertoire dans lequel nous avons ouvert l'archive JAXB téléchargée sur Java.net.
schemagen
. C'est cette tâche qui va nous permettre de lancer la génération de schéma XML.
schema
permet de fixer le nom du fichier XSD généré pour le schéma donné en paramètre. Si ce nom de schéma ne correspond pas au schéma fixé par l'annotation
@XmlRootElement
, alors le nom du fichier n'est pas utilisé.
Exemple 17. Modèle pour la génération d'un schéma
// // énumération Grade // public enum Grade { MATELOT, BOSCO, PACHA, CUISINIER } // // classe Marin // @XmlRootElement(name="marin", namespace="http://www.paumard.org/cours-jaxb") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(propOrder={"nom", "prenom", "grade", "age"}) public class Marin { @XmlAttribute(name="id") private long id ; @XmlElement(required=true) private String nom ; private String prenom ; private long age ; private Grade grade ; // reste de la classe } // // classe Bateau // @XmlRootElement(name="bateau") @XmlAccessorType(XmlAccessType.FIELD) public class Bateau { @XmlAttribute private long id ; private String nom ; @XmlElementWrapper(name="equipage") private List<Marin> equipage = new ArrayList<Marin>() ; // reste de la classe }
marin.xsd
. Il définit l'élément racine
marin
, dans le bon espace de noms.
Exemple 18. Schéma généré, fichier
marin.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xs:schema version="1.0" targetNamespace="http://www.paumard.org/cours-jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:import schemaLocation="schema2.xsd"/> <xs:element name="marin" type="marin"/> </xs:schema>
Exemple 19. Schéma généré, fichier
schema2.xsd
<?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:import namespace="http://www.paumard.org/cours-jaxb" schemaLocation="marin.xsd"/> <xs:element name="bateau" type="bateau"/> <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" nillable="true" minOccurs="0" maxOccurs="unbounded"/> </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>
Bateau
et
Marin
. La lecture de ces types complexes est immédiate : les différents champs des classes sont associés à des éléments XML, et l'on retrouve bien la définition de l'ID en tant qu'attribut.
Notons que les énumérations sont parfaitement supportées par JAXB : la définition de
Grade
est correcte.
Remarquons la façon dont JAXB a pris en compte les contraintes que nous avons posées sur la classe
Marin
, en comparaison de la classe
Bateau
.
Marin
, et il a bien été pris en compte. On remarque que l'ordre est également imposé dans la classe
Capitaine
, alors que nous ne l'avons pas demandé. Effectivement, l'élément
xs:sequence
impose que l'ordre des éléments indiqués soient respecté. Ce n'est pas le cas pour
xs:all
. Il est important de noter ce point.
nom
de la classe
Marin
soit toujours présent. Ce n'est pas le cas pour le même champ de la classe
Bateau
. De fait, dans le schéma XML, on constate que l'élément
nom
peut être absent de l'élément
bateau
. Il doit être présent dans l'élément
marin
(attribut
minOccurs
).
@XmlEnumValue
sur la classe
Grade
. Rappelons que cette annotation impose la valeur de chaque élément de l'énumération.
Exemple 20. Enumération annotée avec
@XmlEnumValue
public enum Grade { @XmlEnumValue("10") MATELOT, @XmlEnumValue("20") BOSCO, @XmlEnumValue("30") PACHA, @XmlEnumValue("40") CUISINIER }
Exemple 21. Schéma généré avec
@XmlEnumValue
<xs:simpleType name="grade"> <xs:restriction base="xs:string"> <xs:enumeration value="10"/> <xs:enumeration value="20"/> <xs:enumeration value="30"/> <xs:enumeration value="40"/> </xs:restriction> </xs:simpleType>
@Path
@Produces
et
@Consumes
@Provider
MessageBodyReader
et
MessageBodyWriter