Introduction
Je vous avais présenté il y a quelques temps Dozer et son utilisation générale, aujourd’hui je vais vous présenter la façon dont j’utilise les « converter » (ou convertisseurs) spécifiques à cet outil de copie d’objets Java.

© http://image.made-in-china.com
Les convertisseurs sont utilisés pour améliorer le mapping entre les objets à copier : lorsque dans le fichier de configuration XML de Dozer une classe A contient un attribut d’une classe B et qu’un convertisseur est nommé pour effectuer cette transformation alors c’est celui-ci qui est utilisé et non le le mapping de base de Dozer.
Utilisation standard
Lorsque le mapping entre deux classes est un peu complexe ou que Dozer, par défaut, ne permet pas de faire ce que l’on souhaite, alors les convertisseurs sont très utiles et efficaces.
Prenons un exemple simple : vous voulez convertir un objet de type java.lang.Boolean en java.lang.String et que le la valeur TRUE du premier devienne un « YES » et que la valeur FALSE un « NO » (et vice versa), voici comment procéder :
- Fichier de configuration XML
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- Dozzer mapper --> <bean id="dozerMapper" class="org.dozer.DozerBeanMapper"> <description>Dozer Mapper with mapping files and custom converters</description> <property name="mappingFiles"> <list> <value>desgeeks-dozer-config.xml</value> </list> </property> <property name="customConvertersWithId"> <map> <entry key="booleanConverterId" value-ref="booleanConverter" /> </map> </property> </bean> <!-- custom converter --> <bean id="booleanConverter" class="fr.mtg.unit.presentation.converter.BooleanConverter"> <description>Converter to convert Boolean to String (TRUE <=> "YES", FALSE <=> "NO")</description> </bean> </beans>
- Fichier de mapping (desgeeks-dozer-config.xml)
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd">
<!-- ClassA to ClassB -->
<mapping>
<class-a>votre.package.de.class.ClassA</class-a>
<class-b>votre.package.de.class.ClassB</class-b>
<field>
<a>id</a>
<b>identifiant</b>
</field>
<field custom-converter-id="booleanConverterId">
<a>authorized</a>
<b>estAutorise</b>
</field>
</mapping>
</mappings>
- Convertisseur Java
import org.dozer.DozerConverter;
public class BooleanConverter extends DozerConverter<Boolean, String> {
public BooleanConverter() {
super(Boolean.class, String.class);
}
@Override
public Boolean convertFrom(String paramB, Boolean paramA) {
if ("YES".equalsIgnoreCase(paramB)) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
@Override
public String convertTo(Boolean paramA, String paramB) {
if (paramA != null && paramA.equals(Boolean.TRUE)) {
return "YES";
}
return "NO";
}
}
Utilisation avancée
Etant donné que lorsqu’un convertisseur est nommé dans le fichier de mapping de Dozer c’est celui-ci qui est utilisé et plus le mapping de base pour la copie des attributs, cela veut dire que nous devons refaire le mapping pour chaque champ de notre objet à l’intérieur même du convertisseur.
Voici la solution que j’utilise pour s’affranchir du mapping « basique » afin de s’occuper, dans mes convertisseurs, uniquement des traitements spécifiques que Dozer ne peut faire naturellement.
Pour cela j’injecte le bean Spring dozerMapper dans mes bean ‘converter’ pour que les méthodes « convertTo » et « convertFrom » puissent appeler le mapping standard de Dozer avant d’effectuer des conversions spécifiques :
@Override
public CardRemote convertTo(Card paramA, CardRemote paramB) {
// dozer standard mapping
CardRemote cardRemote = (CardRemote) mapper.map(paramA, CardRemote.class);
// card images
cardRemote.setImageNormal(ImageUtil.getSourceImageCard(paramA, ImageUtil.CARD_IMAGE_NORMAL));
cardRemote.setImageBig(ImageUtil.getSourceImageCard(paramA, ImageUtil.CARD_IMAGE_BIG));
cardRemote.setManaCostAsImage(ImageUtil.replaceSymbolCodeBySourceImage(paramA.getManaCost()));
cardRemote.setTextAsImage(ImageUtil.replaceSymbolCodeBySourceImage(paramA.getText()));
return cardRemote;
}
Cela permet d’appeler en premier la copie de l’objet Card vers CardRemote par le biais du mapping Dozer :
<!-- Card to CardRemote -->
<mapping>
<class-a>fr.mtg.unit.domain.model.Card</class-a>
<class-b>fr.mtg.unit.presentation.remote.CardRemote</class-b>
<field>
<a>pkCard</a>
<b>id</b>
</field>
<field>
<a>manaCost</a>
<b>manaCostAsText</b>
</field>
<field>
<a>text</a>
<b>textAsText</b>
</field>
<field>
<a>cardLink.englishCard</a>
<b>englishCardId</b>
</field>
<field>
<a>cardLink.frenchCard</a>
<b>frenchCardId</b>
</field>
<field custom-converter-id="setConverterId">
<a>set</a>
<b>set</b>
</field>
</mapping>
puis d’effectuer des traitements spécifiques de conversion de l’objet Card vers CardRemote.
Pour le convertisseur « setConvertId » nommé dans ci-dessus, je procède de la même façon pour que tout se fasse tout seul
Conclusion
L’avantage de la seconde solution est qu’à présent vous pouvez utiliser directement vos classes « converter » dans vos propres classes utilitaires car ceux-ci comprennent déjà le mapping de Dozer qui est appelé implicitement dans vos méthodes « convertTo » et « convertFrom ».
Je ne sais pas si beaucoup d’entre vous utilisent Dozer dans vos architectures distribuées mais pour ma part c’est un « must have », à vous de tester !




Affichez votre portrait
{ 2 commentaires… à vous de vous exprimer ! }
« Mais à quoi ça sert de transvaser les données de mon objet vers un autre ? » Nan je rigole, tu donnes la réponse à cette question dans ton premier article ici
Klr, il est chouette cet outil, j’ai déjà converti mes collègues de bureau à l’utiliser dans leur projet perso
^^