Listes de mappage avec ModelMapper

1. Vue d'ensemble

Dans ce didacticiel, nous expliquerons comment mapper des listes de différents types d'éléments à l'aide du framework ModelMapper. Cela implique l'utilisation de types génériques en Java comme solution pour convertir différents types de données d'une liste à une autre .

2. Model Mapper

Le rôle principal de ModelMapper est de mapper des objets en déterminant comment un modèle d'objet est mappé à un autre appelé objet de transformation de données (DTO).

Pour utiliser ModelMapper, nous commençons par ajouter la dépendance à notre pom.xml :

 org.modelmapper modelmapper 2.3.7 

2.1. Configuration

ModelMapper fournit une variété de configurations pour simplifier le processus de mappage. Nous personnalisons la configuration en activant ou en désactivant les propriétés appropriées dans la configuration. Il est courant de définir la propriété fieldMatchingEnabled sur true et d'autoriser la correspondance de champ privé :

modelMapper.getConfiguration() .setFieldMatchingEnabled(true) .setFieldAccessLevel(Configuration.AccessLevel.PRIVATE); 

Ce faisant, ModelMapper peut comparer des champs privés dans les classes de mappage (objets). Dans cette configuration, il n'est pas strictement nécessaire que tous les champs portant le même nom existent dans les deux classes. Plusieurs stratégies de correspondance sont autorisées. Par défaut, une stratégie de correspondance standard nécessite que toutes les propriétés source et destination soient mises en correspondance dans n'importe quel ordre. C'est idéal pour notre scénario .

2.2. Jeton de type

ModelMapper utilise TypeToken pour mapper des types génériques. Pour voir pourquoi cela est nécessaire, voyons ce qui se passe lorsque nous mappons une liste d' entiers à une liste de caractères :

List integers = new ArrayList(); integers.add(1); integers.add(2); integers.add(3); List characters = new ArrayList(); modelMapper.map(integers, characters);

De plus, si nous imprimons les éléments de la liste de caractères, nous verrons une liste vide. Cela est dû à l'occurrence de l'effacement de type lors de l'exécution du runtime.

Si nous changeons notre appel de carte pour utiliser TypeToken , cependant, nous pouvons créer un littéral de type pour List :

List characters = modelMapper.map(integers, new TypeToken
    
     () {}.getType());
    

Au moment de la compilation, la casse interne anonyme TokenType préserve le type de paramètre List , et cette fois, notre conversion est réussie.

3. Utilisation du mappage de type personnalisé

Les listes en Java peuvent être mappées à l'aide de types d'éléments personnalisés.

Par exemple, disons que nous voulons mapper une liste d' entités User à une liste UserDTO . Pour ce faire, nous appellerons map pour chaque élément:

List dtos = users .stream() .map(user -> modelMapper.map(user, UserDTO.class)) .collect(Collectors.toList());

Bien sûr, avec un peu plus de travail, nous pourrions créer une méthode paramétrée à usage général:

 List mapList(List source, Class targetClass) { return source .stream() .map(element -> modelMapper.map(element, targetClass)) .collect(Collectors.toList()); }

Donc, alors, nous pourrions plutôt faire:

List userDtoList = mapList(users, UserDTO.class);

4. Type de carte et mappage de propriété

Des propriétés spécifiques telles que des listes ou des ensembles peuvent être ajoutées au modèle User-UserDTO . TypeMap fournit une méthode pour définir explicitement le mappage de ces propriétés. L' objet TypeMap stocke les informations de mappage de types (classes) spécifiques:

TypeMap typeMap = modelMapper.createTypeMap(UserList.class, UserListDTO.class);

La classe UserList contient une collection d' utilisateurs . Ici, nous voulons mapper la liste des noms d'utilisateur de cette collection à la liste des propriétés de la classe UserListDTO . Pour ce faire, nous allons créer la première classe UsersListConverter et lui transmettre List et List comme types de paramètres pour la conversion:

public class UsersListConverter extends AbstractConverter
    
      { @Override protected List convert(List users) { return users .stream() .map(User::getUsername) .collect(Collectors.toList()); } }
    

À partir de l' objet TypeMap créé, nous ajoutons explicitement Property Mapping en appelant une instance de la classe UsersListConverter :

 typeMap.addMappings(mapper -> mapper.using(new UsersListConverter()) .map(UserList::getUsers, UserListDTO::setUsernames));

Dans la méthode addMappings , un mappage d'expression nous permet de définir les propriétés source vers destination avec des expressions lambda. Enfin, il convertit la liste des utilisateurs en liste résultante de noms d'utilisateur.

5. Conclusion

Dans ce didacticiel, nous avons expliqué comment les listes sont mappées en manipulant des types génériques dans ModelMapper . Nous pouvons utiliser TypeToken, le mappage de type générique et le mappage de propriétépour créer des types de liste d'objets et réaliser des mappages complexes.

Le code source complet de cet article est disponible à l'adresse over sur GitHub.