Carlos Julian Grisales Alvarez
Luis Brandon Flores González
Gonzalo Antonio Rojas Mardones
¿Cómo crear un paquete y una interfaz para los mapeadores?
Al trabajar en desarrollos de software, es esencial contar con herramientas que faciliten la transformación de datos entre diferentes capas del sistema. Una de esas herramientas es MapStruct, que nos permitirá generar mapeadores para traducir objetos de dominio a entidades y viceversa. Para comenzar, debemos:
Mapper.CategoryMapper y ProductMapper.Esto se hace seleccionando "new package" y posteriormente "new interfaz" en nuestro IDE. Estos mapeadores serán fundamentales para asegurar que las conversiones se realicen de manera eficiente y precisa.
¿Qué anotaciones se deben utilizar en un mapeador?
MapStruct nos ofrece una sintaxis clara y precisa para definir nuestras conversiones:
Definir estas anotaciones garantiza que MapStruct gestione correctamente la creación de instancias de mapeadores y su integración con el ciclo de vida de Spring.
¿Cómo definir métodos de conversión?
Los métodos de conversión transforman un tipo de objeto en otro. Aquí definimos métodos para convertir Category y Product en sus equivalentes del dominio.
Conversión de Category a categoría
@Mapper(componentModel = "spring") public interface CategoryMapper { @Mapping(source = "idCategoria", target = "categoryId") @Mapping(source = "descripcion", target = "category") @Mapping(source = "estado", target = "active") Category toCategory(Categoria categoria); }
Aquí, @Mapping configura cómo se mapean fielmente los datos desde idCategoria, descripcion, y estado hacia sus respectivos atributos en la entidad Category.
Conversión inversa y manejo de atributos ignorados
Para realizar mapeos inversos (de Category a Categoria) y asegurarse de ignorar ciertos atributos que no son necesarios en el lado de la entidad, MapStruct permite el uso de:
@Mapping(target = "productos", ignore = true)
Implementar estas configuraciones limita el código redundante y simplifica el manejo de atributos compatibles entre sistemas.
¿Cómo usar mapeadores para productos?
La interfaz ProductMapper sigue un diseño similar:
Metodología de mapeo
@Mapper(componentModel = "spring", uses = CategoryMapper.class) public interface ProductMapper { @Mappings({ @Mapping(source = "idProducto", target = "productId"), @Mapping(source = "nombre", target = "name"), @Mapping(source = "precioVenta", target = "price"), @Mapping(source = "cantidadStock", target = "stock"), @Mapping(source = "estado", target = "active"), @Mapping(source = "categoria", target = "category") }) Product toProduct(Producto producto); }
Aquí, aseguramos la transformación precisa de cada atributo, utilizando CategoryMapper para manejar las conversiones involucradas con el atributo categoria.
Manejo de listas y conversión inversa
La interfaz también debería incluir métodos para manejar listas de productos y realizar la conversión inversa:
List<Product> toProducts(List<Producto> productos); @InheritInverseConfiguration Producto toProducto(Product product); @Mapping(target = "codigoBarras", ignore = true)
Estos métodos optimizan la gestión de múltiples productos y aseguran que todos los casos de uso de conversión están cubiertos de manera eficiente.
¿Qué beneficios ofrece MapStruct en el desarrollo?
MapStruct simplifica la configuración de mapeadores, lo que reduce el tiempo de desarrollo e incrementa la legibilidad, mantenibilidad y precisión de las conversiones de datos. Incentiva a los desarrolladores a estructurar su código de manera modular y reutilizable.
Reflexionar sobre cómo estos mapeadores integran diferentes capas en tu aplicación te abrirá a implementar soluciones más efectivas y robustas en futuros proyectos. Continúa explorando y dominando herramientas como MapStruct para maximizar la eficiencia de tu desarrollo.
Carlos Julian Grisales Alvarez
Luis Brandon Flores González
Gonzalo Antonio Rojas Mardones
Josué Isaac Fuentes López
Cristian David Restrepo Marin
Giovanni Alzate
David Gallego
Rolando Mamani Salas
Alejandro Rico García
Froylan Daniel Aguilar Flores
Alejandro Rico García
Beni García
Enrique Quiroz
Cristhian David Gallo Medina
Raul Salvo
Elio Esteban Tapia Peña
Yoexer Elias Moran Urcia
Sebastián Pineda Duque
Fausto Almeida Campos
Andrés Orlando Orduz Grimaldo
Rolando Mamani Salas
Alejandro Tangarife Rivas
Jeffersson Muñoz Torres
Jean Michael Lozano Cardoso
Nicoll Idaly Angulo Mejia
Yasniel Fajardo Egues
Juan Calderón
Andrés Orlando Orduz Grimaldo
Cristian Triviño Estévez
Joel Campos
Alejandro Ramírez
ProfesorJuan Esteban Escobar Restrepo
David Jordan
Pablo Ochoa
Alejandro Rico García
Juan Pablo Guirado
Jaime Cárdenas Mesa
Alejandro Ramírez
ProfesorNo hice caso al viajero del tiempo de no tratar de implementar la Aplicación en Inglés desde el principio :) A rehacer, mejor más aprendemos!
Jajaja me paso lo mismo, por eso me regrese a la clase donde empezaba a implementar en español y puse el mensaje para que no cometieron el error los demás. P.D. Soy el viajero del tiempo jaja...
No es necesario rehacer todo y escribirlo en español, basta que las clase Category que creaste en el package Domain nombrarla DomainCategory y se resuelve el problema de import.
Esto del mapper, si me revento la cebeza
x2
x3
Excelente! Me impresiona la manera en la que mapstruct simplifica el código.
La verdad es muy buena la explicacion del profesor
En java antes de saber que existe mapStruct usaba ModelMapper, el uso es mas simple en modelMapper si se trata de convertir clases con atributos con el mismo nombre por ejemplo de Categoria a CategoriaDto con los mismos atributos, veo que con mapStruct la configuracion es mucho más simple para indicar por ejemplo en este caso atributo con atributo de diferente nombre.
Gracias! que buena comparativa, ya había usado dozer y modelmapper, ahora el favorito es mapstruct.
A alguien mas al compilar les dice que productos no está dentro de categoria?
Me sale lo mismo Bro,
ALGUNO ENCONTRO COMO ARREGLAR EL PROBLEMA?
Bendito viajero del tiempo.
Si les marca error al hacer el mapeo de categorias y productos a mi me lo soluciono el poner los setters y getters
Gracias, solucionó el error
Creación de mappers
Creación de paquete llamado “mapper” en el paquete “persistence”.
Se crean como interface
A cada clase se le añade el sufijo “Mapper”.
Se le añade a la clase la anotación @Mapper
MapStruct nos ofrece una integración con Spring. Se le especifica a la anotación: @Mapper(componentModel = "spring")
Se especifica la conversión: Category toCategory(Categoria categoria);. Se convertirá un entity de tipo Categoria a un dominio de tipo Category.
Se añade la siguiente estructura de anotaciones:
@Mappings({ @Mapping(source = "idCategoria", target = "categoryId"), @Mapping(source = "descripcion", target = "category"), }) Category toCategory(Categoria categoria);
Se debe hacer el mapeo en sentido contrario. Con la anotación @InheritInverseConfiguration
@Mapping(target = "productos", ignore = true)@InheritInverseConfiguration @Mapping(target = "productos", ignore = true) Categoria toCategoria(Category category);
Cuando se mapea un atributo que es de una clase que tiene su mapper propio, dentro de la anotación @Mapper, se añade algo como lo siguiente: @Mapper(componentModel = "spring", uses = {CategoryMapper.class})
Muy buen aporte! Ejemplos muy útiles para aprovechar mapstruct.
Codigo de la clase
@Mapper(componentModel = "spring") public interface CategoryMapper { @Mappings({ @Mapping(source = "idCategoria", target = "categoryId"), @Mapping(source = "descripcion", target = "category"), @Mapping(source = "estado", target = "active"), }) Category toCategory(Categoria categoria); @InheritInverseConfiguration @Mapping(target = "productos", ignore = true) Categoria toCategoria(Category category); }
para ignorar un atributo se escribe el siguiente codigo , se ignora los campos que se relacciona con otras tablas o campos que no necesitemos, siempre se debe ignorar si no se agrega en los campos Mappings
@Mapping(target = "nombreCampo", ignore = true)
Muchas gracias
Tengo entendido que a la hora de crear Interfaces es buena practica anteponer una i mayúscula, para denotar que se trata de una interfaz y no una clase.
Algo así Interface: ICategoryMapper -> fijense en la (i) que viene primero.
No sabria si estoy 100% en lo correcto pero el detalle del i se usa cuando es una interfaz de comportamiento de objeto, en cambio, cuando son interfaces de estructura los nombras con el proposito de este solamente
Para los que tengan problemas con el @Data de lombok, nn vez de usar @Data se deben usar @Getter y @Setter, así el lombok no genera problemas. Adicional colocar annotationProcessor:
implementation 'org.projectlombok:lombok:1.18.22' annotationProcessor 'org.projectlombok:lombok:1.18.22'
Dudo mucho que en un proyecto real exista el espanglish que hay metido aqui, esto es un desastre, en mi opinion :(
Creería que lo mejor es usar todo en inglés y en caso de tener dos clases con el mismo nombre, usar una con un sufijo
@Mapper(componentModel = "spring", uses = {CategoryMapper.class}) public interface ProductMapper { @Mappings({ @Mapping(source = "idProducto", target = "productId"), @Mapping(source = "nombre", target = "name"), @Mapping(source = "idCategoria", target = "categoryId"), @Mapping(source = "precioVenta", target = "price"), @Mapping(source = "cantidadStock", target = "stock"), @Mapping(source = "estado", target = "active"), @Mapping(source = "categoria", target = "category"), }) Product toProduct(Producto producto); List<Product> toProducts(List<Producto> productos); @InheritInverseConfiguration @Mapping(target = "codigoBarras", ignore = true) Producto toProducto(Product product); }
Para indicarle a Spring que tiene que pasar el campo categoria a Category debe usar CategoryMapper.class
@Mapper(componentModel = "spring", uses = {CategoryMapper.class})
A la hora de compilar el proyecto o ejecutarlo me da un error la línea
@Mapping(target = "productos", ignore = true)
de que en mi clase Categoria no existe el atributo "productos":
error: Unknown property "productos" in result type com.platzimarket.persistence.entity.Categoria. Did you mean "estado"? @Mapping(target = "productos", ignore = true) ^
En mi clase Categoria si existe el atributo productos, como una List (al igual que al código que muestras y proporcionas). ¿Es un error importante o no debo tenerlo en cuenta ahora mismo? Comentando la línea me corre perfecto el proyecto hasta ahora
¡Muchas gracias de antemano! 😀
Verifica si tienes todos los setters y getters, yo también tenia ese error.
El mapeo se realiza gracias a los getters y setters de la clase. El atributo productos tiene los métodos get y set? Estoy casi seguro que es eso.
Tip: Cuando usas una versión de java posterior a la 8 puedes evitar el agrupamiento de anotaciones y simplemente puedes declararlas tal cual una después de otra.
por ejemplo:
Fuente: SonarLint
Si las variables se llaman igual, no es necesario hacer el @Mapping. La utilidad sería entonces por ejemplo no mapear algunas variables (en este caso el código de barras, por ejemplo).
A veces algunas columnas se llaman igual y otras no, por ejemplo "email" a veces lo llaman igual en bases de datos en español, entonces no sería necesario hacer el mapping de esta.
Buenas no me carga el vídeo 22, pase al vídeo 23 y funciona perfecto
Cambia el servidor en el engrane dentro del área del video.
Alejandro que tal, primero quiero felicitarte por la calidad de tus cursos, me han servido enormemente. Tengo un error cuando quiero cargar la aplicacion, me lo arroja en la linea de la interfaz ProductMapper donde va el @Mapping(source = "categoria", target = "category"), y por consola me dice que no existe una propiedad llamada categoria en el result type Producto. Pense que para esto se utilizaba el uses={CategoryMapper.class}. Agradezco tu ayuda!
Amigo, siempre que hagas una pregunta, trata de dar el mayor contexto posible, como por ejemplo adjuntando fotos de tu código y del error, así nos será mas fácil ayudarte a cualquier otra persona, si me das mas contexto con gusto intentare ayudarte a resolver tu Problema!
Hola Juan Pablo, muchas gracias!
Ya pusiste el get y set de Categoria dentro de la clase Producto? Quizás sea eso.