1. Información general
En este tutorial, explicaremos cómo mapear listas de diferentes tipos de elementos utilizando el marco ModelMapper. Esto implica el uso de tipos genéricos en Java como solución para convertir diferentes tipos de datos de una lista a otra .
2. Model Mapper
La función principal de ModelMapper es mapear objetos determinando cómo se asigna un modelo de objeto a otro llamado Objeto de transformación de datos (DTO).
Para usar ModelMapper, comenzamos agregando la dependencia a nuestro pom.xml :
org.modelmapper modelmapper 2.3.7
2.1. Configuración
ModelMapper proporciona una variedad de configuraciones para simplificar el proceso de mapeo. Personalizamos la configuración habilitando o deshabilitando las propiedades apropiadas en la configuración. Es una práctica común establecer la propiedad fieldMatchingEnabled en true y permitir la coincidencia de campos privados :
modelMapper.getConfiguration() .setFieldMatchingEnabled(true) .setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
Al hacerlo, ModelMapper puede comparar campos privados en las clases de mapeo (objetos). En esta configuración, no es estrictamente necesario que todos los campos con los mismos nombres existan en ambas clases. Se permiten varias estrategias coincidentes. De forma predeterminada, una estrategia de coincidencia estándar requiere que todas las propiedades de origen y destino coincidan en cualquier orden. Esto es ideal para nuestro escenario .
2.2. Tipo Token
ModelMapper usa TypeToken para mapear tipos genéricos. Para ver por qué esto es necesario, veamos qué sucede cuando asignamos una lista de enteros a una lista de caracteres :
List integers = new ArrayList(); integers.add(1); integers.add(2); integers.add(3); List characters = new ArrayList(); modelMapper.map(integers, characters);
Además, si imprimimos los elementos de la lista de caracteres , veríamos una lista vacía. Esto se debe a la ocurrencia del borrado de tipo durante la ejecución en tiempo de ejecución.
Sin embargo, si cambiamos nuestra llamada de mapa para usar TypeToken , podemos crear un literal de tipo para List :
List characters = modelMapper.map(integers, new TypeToken
() {}.getType());
En el momento de la compilación, el caso interno anónimo TokenType conserva el tipo de parámetro List , y esta vez nuestra conversión es exitosa.
3. Uso de la asignación de tipos personalizados
Las listas en Java se pueden asignar utilizando tipos de elementos personalizados.
Por ejemplo, digamos que queremos mapear una lista de entidades de usuario a una lista de UserDTO . Para lograr esto, llamaremos map para cada elemento:
List dtos = users .stream() .map(user -> modelMapper.map(user, UserDTO.class)) .collect(Collectors.toList());
Por supuesto, con un poco más de trabajo, podríamos hacer un método parametrizado de propósito general:
List mapList(List source, Class targetClass) { return source .stream() .map(element -> modelMapper.map(element, targetClass)) .collect(Collectors.toList()); }
Entonces, entonces, podríamos hacer:
List userDtoList = mapList(users, UserDTO.class);
4. Escriba Mapa y asignación de propiedades
Se pueden agregar propiedades específicas como listas o conjuntos al modelo User-UserDTO . TypeMap proporciona un método para definir explícitamente la asignación de estas propiedades. El objeto TypeMap almacena información de mapeo de tipos específicos (clases):
TypeMap typeMap = modelMapper.createTypeMap(UserList.class, UserListDTO.class);
La clase UserList contiene una colección de User s. Aquí, queremos mapear la lista de nombres de usuario de esta colección a la lista de propiedades de la clase UserListDTO . Para lograr esto, crearemos la primera clase UsersListConverter y le pasaremos List y List como tipos de parámetros para la conversión:
public class UsersListConverter extends AbstractConverter
{ @Override protected List convert(List users) { return users .stream() .map(User::getUsername) .collect(Collectors.toList()); } }
Desde el objeto TypeMap creado, agregamos explícitamente Property Mapping invocando una instancia de la clase UsersListConverter :
typeMap.addMappings(mapper -> mapper.using(new UsersListConverter()) .map(UserList::getUsers, UserListDTO::setUsernames));
Dentro del método addMappings , un mapeo de expresión nos permite definir las propiedades de origen a destino con expresiones lambda. Finalmente, convierte la lista de usuarios en la lista resultante de nombres de usuario.
5. Conclusión
En este tutorial, explicamos cómo se mapean las listas mediante la manipulación de tipos genéricos en ModelMapper . Podemos hacer uso de TypeToken, mapeo de tipos genéricos y mapeo de propiedadespara crear tipos de listas de objetos y realizar mapeos complejos.
El código fuente completo de este artículo está disponible en GitHub.