Comment intégrer JAXB avec MAVEN et SPRING


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 POM

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>
Le fichier Spring

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>
Code JAVA

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 =&gt; 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. #1 by Mohamed on 14 juillet 2011 - 11:54

    Très utile ton article, c’est Lilli-rose qui a corrigée?

  2. #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.

(ne sera pas publié)