Ce billet a pour origine un commentaire posté dans
mon précédent billet
et dans lequel Laurent demandait un
retour d’expérience
sur l’utilisation de
frameworks Java de mapping objet vers objet
tels
Dozer
ou
ModelMapper
.
Dans l’architecture d’une
applicative n-tiers
, une couche de mapping objet / objet peut intervenir à plusieurs niveaux :
En entrée ou en sortie d’un web service SOAP afin de convertir en objet métier les DTO générés à partir du WSDL, ou inversement.
Entre la couche de présentation et la couche de services métiers lorsque la première expose des DTO et la seconde travaille avec des objets métiers.
Entre la couche de services métiers et la couche d’accès aux données afin de mapper les entités persistances en objets métiers.
Dans le premier exemple, le développeur n’a guère le choix. Dans les 2 autres, il s’agit d’un choix d’architecture.
L’introduction d’une couche de mapping n’est pas un choix à prendre à la légère : ayant pour objectif de découpler les couches, elle complexifie l’application et peut détériorer ses performances. Le choix d’en introduire une et d’utiliser un framework pour faciliter sa mise en œuvre n’est pas non plus évident.
Ce billet est découpé en 2 parties :
Une première dressant les
avantages
et les
inconvénients
d’utiliser
Dozer
par rapport à une
approche manuelle
,
et une seconde présentant les résultats d’un
micro-benchmark
comparant plusieurs frameworks :
Dozer
,
Orika
,
Selma
,
MapStruct
et
ModelMapper
.
Tableau comparatif Dozer vs mapping manuel en Java
Extrait d’un
retour d’expérience
, le tableau ci-dessous dresse les avantages et les inconvénients de Dozer par rapport à une approche manuelle. A vous de pondérer chaque avantage / inconvénient en fonction de vos exigences.
Lisibilité du XML pour mapper les champs : profondeur du chemin de la propriété, découplage entre la correspondance source/destination et la règle de transformation, conversion implicite en fonction des types source et destination
Réutilisation du code : transformations réutilisables
Structure le développement de mappings
Le mapping sert à la fois pour créer un nouvel objet et compléter un objet existant
Mapping bi-directionnel offert
Faibles performances
Mapping non compilé : pas de complétion dans l’IDE, refactoring nécessitant des recherches dans le XML
Utilisation de converter pour gérer les cas compliqués (et ne pas faire appel à du code Java après le mapping Dozer).
Apprentissage du framework et des bonnes pratiques
En fonction de votre expertise, ce tableau pourrait être adapter avec d’autres frameworks.
Quelque soit l’approche choisie (framework ou code manuel), seuls des
tests unitaires
permettront de valider le mapping. Ne pouvant être automatisés, ces tests s’avèrent malheureusement longs et fastidieux.
Micro-benchmark
Ne trouvant aucun comparatif récent sur les performances des frameworks de mapping, j’ai créé sur GitHub le projet
java-object-mapper-benchmark
. Ce dernier utilise
JMH
(Java Microbenchmarking Harness) pour réaliser un micro-benchmark entre Dozer, Selma, ModelMapper, Orika, MapStruct et un mapping écrit manuellement.
Le diagramme ci-dessous présente résultats obtenus avec la configuration suivante :
OS: MacOSX
CPU: Core i7 2.8GHz 6MB cache × 4 cores
RAM: 16GB
JVM: Oracle 1.8.0_25 64 bits
Comme on pouvait s’y attendre, les performances du code écrit à la main sont les meilleures.
Selma et MapStruct se rapprochent le plus des performances d’un code écrit manuellement. Ce résultat s’explique par le fait qu’ils génèrent le code source à l’aide de l’
Annotation Processor
introduit par Java 6 (JSR-269).
Basés sur l’
introspection
de code, Dozer et ModelMapper sont peu performants.
Entre ces 2 catégories, on retrouve Orika qui utilise au runtime l’API
Java Compiler
pour générer le code du mapping.
Pour exécuter vous même le benchmark, Maven, un JDK et 3 lignes de commandes suffisent :
git clone git://github.com/arey/java-object-mapper-benchmark.git
mvn clean install
java -jar target/benchmarks.jar
Conclusion
En 2015, l’utilisation d’un framework de mapping objet / objet basé sur la génération de code plutôt que sur l’introspection semble préférable. Non seulement les performances sont bien meilleures, mais le couplage avec le framework est faible puisqu’il est possible de le supprimer et de conserver dans votre SCM le code généré.
Selma
et
MapStruct
sont les 2 gagnants du benchmark.
Encore une fois, avant de partir sur une telle approche, prenez un temps de réflexion. Des entités métiers annotées avec Bean Validation et traversant l’ensemble des couches restent l’architecture la plus simple à mettre en œuvre. Je suis déjà intervenu sur une application où une couche de mapping avait été mise en œuvre dès le départ pour des raisons de découplage, puis retirée au fur et à mesure car sa plus value était trop faible.
Références
:
Dozer vs Orika vs Manual (2013)
Java Bean Mapper Performance Tests
(2007)
Selma, le mapping Java à la compilation
(2014)
Using JMH for Java Microbenchmarking
(2013)