Pourquoi utiliser JAXB ?
Au fil du temps, JAXB est devenu le standard. En effet, il est désormais intégré au langage java depuis la version 6. Son utilisation est clairement simplifiée, car plus aucun jar externe n’est requis. On économise ainsi du temps dans la gestion de dépendances et les applications sont moins lourde en terme de taille.
Maven pour quoi faire?
Le plug-in maven-jaxb2-plugin est très intéressant, car il nous permet de paramétrer la génération des classes au moment du build. Il permet également de gérer assez finement les paramètres des packages de destination tel que le nommage personnalisé ou le fait d’en générer plusieurs. Il permet entre autre de pouvoir inclure ou exclure des schémas XSD. Il est aussi intéressant d’utiliser maven pour ses capacités de gestion de dépendances.
Pourquoi rajouter la couche spring ?
Spring permet cette intégration afin de bien découper son code. En effet, le code dit « technique » tel que les appels au contexte et à la factory de JAXB est externalisé dans un fichier de configuration. Cela permet au dévloppeur de se concentrer uniquement sur du code « fonctionnel » et ne pas voir ses classes polluées par du « câblage » technique.
Un exemple vaut mieux que 1000 mots !
L’exemple ci-dessous illustre le mapping
- Objet -> XML
- XML -> Objet
Le fichier XML
Le fichier décrit une banque qui contient plusieurs comptes. Ces comptes sont composés d’un propriétaire et d’un solde.
<bank> <account> <owner>Toto/owner> <balance>132.7</balance> </account> <account> <owner>Titi/owner> <balance>28.89</balance> </account> </bank>
Le schéma XSD
Voici son fichier XSD associé.
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="bank"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="account"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="account"> <xs:complexType> <xs:sequence> <xs:element ref="owner"/> <xs:element ref="balance"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="owner" type="xs:string"/> <xs:element name="balance" type="xs:decimal"/> </xs:schema>
Le fichier complet décrivant les dépendances et les plugins
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ch.illuminit</groupId> <artifactId>JAXB</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <spring.version>3.0.5.RELEASE</spring.version> <apache.commons.collection.version>3.2.1</apache.commons.collection.version> <apache.commons-pool-version>20030825.183949</apache.commons-pool-version> <jaxb.plugin.version>0.7.5</jaxb.plugin.version> <maven.plugin.compiler.version>2.0.2</maven.plugin.compiler.version> <java.version>1.6</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jaxb.package>ch.illuminit.bank</jaxb.package> <jaxb.directory>src/main/resources/xsd</jaxb.directory> <jaxb.binding.directory>src/main/resources/xjb/bindings.xjb</jaxb.binding.directory> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>${apache.commons.collection.version}</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>${apache.commons-pool-version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.jvnet.jaxb2.maven2</groupId> <artifactId>maven-jaxb2-plugin</artifactId> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> <version>${jaxb.plugin.version}</version> <configuration> <generatePackage>${jaxb.package}</generatePackage> <schemaDirectory>${jaxb.directory}</schemaDirectory> <bindingFiles> <bindingFile>${jaxb.binding.directory}</bindingFile> </bindingFiles> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.plugin.compiler.version}</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> </plugins> </build> </project>
C’est grâce à ce fichier que spring crée les objets JAXB
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="ch.illuminit"/> <bean id="jaxbContext" class="javax.xml.bind.JAXBContext" factory-method="newInstance"> <constructor-arg> <list> <value type="java.lang.Class">ch.illuminit.bank.Bank</value> </list> </constructor-arg> </bean> <bean id="marshallerTarget" class="javax.xml.bind.Marshaller" factory-bean="jaxbContext" factory-method="createMarshaller" scope="prototype"> </bean> <bean id="unmarshallerTarget" class="javax.xml.bind.Unmarshaller" factory-bean="jaxbContext" factory-method="createUnmarshaller" scope="prototype"> </bean> <bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource"> <property name="targetBeanName" value="marshallerTarget" /> <property name="maxSize" value="25" /> </bean> <bean id="unmarshallerPoolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource"> <property name="targetBeanName" value="unmarshallerTarget" /> <property name="maxSize" value="25" /> </bean> <bean id="marshaller" class="org.springframework.aop.framework.ProxyFactoryBean"> <qualifier value="marshaller" /> <property name="targetSource" ref="poolTargetSource" /> </bean> <bean id="unmarshaller" class="org.springframework.aop.framework.ProxyFactoryBean"> <qualifier value="unmarshaller" /> <property name="targetSource" ref="unmarshallerPoolTargetSource" /> </bean> </beans>
Pour ce tutoriel, j’ai décidé d’utiliser les annotations de spring afin d’injecter le marshaller et le unmarshaller
package ch.illuminit.jaxb; import ch.illuminit.bank.Bank; import java.io.File; import java.io.StringWriter; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * @author Benoît Julita */ @Service public class BankService { @Autowired private Unmarshaller unmarshaller; @Autowired private Marshaller marshaller; // PATH TO : bank.xml => xml/bank.xml private String path = path = Thread.currentThread() .getClass().getResource("/xml/bank.xml").getPath(); public Bank marshall() { try { Bank bank = (Bank) unmarshaller.unmarshal(new File(path)); return bank; } catch (JAXBException ex) { //do something... } return null; } public String unmarshall(Bank bank) { StringWriter sw = new StringWriter(); try { marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); marshaller.marshal(bank, sw); } catch (JAXBException ex) { //do something } return sw.toString(); } }
On lance une petite appli pour tester la bête!
package ch.illuminit.jaxb; import ch.illuminit.bank.Account; import ch.illuminit.bank.Bank; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author Benoît Julita */ public class App { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("classpath:spring/jaxb-context.xml"); BankService service = context.getBean(BankService.class); Bank bank = service.marshall(); for (Account current : bank.getAccount()) { System.out.println(current.getOwner()); System.out.println(current.getBalance()); } bank.getAccount().get(0).setOwner("neoToto"); System.out.println(service.unmarshall(bank)); } }
Voici l’output
Toto
132.7
Titi
28.89
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bank>
<account>
<owner>neoToto</owner>
<balance>132.7</balance>
</account>
<account>
<owner>Titi</owner>
<balance>28.89</balance>
</account>
</bank>Références
http://axixmiqui.wordpress.com/2009/09/01/spring-injecting-jaxb-unmarshaller/
#1 by Mohamed on 14 juillet 2011 - 11:54
Très utile ton article, c’est Lilli-rose qui a corrigée?
#2 by Pavel on 15 novembre 2011 - 12:52
Bien ton article l’artiste.
Juste une précision: conceptuellement parlant les méthodes marshall et unmarshall sont inversées.