MapStruct for object mapping

David Kumar Jan 2026
3 tabs
package com.example.demo.mapper;

import com.example.demo.dto.UserDTO;
import com.example.demo.model.User;
import org.mapstruct.*;

import java.util.List;

@Mapper(componentModel = "spring")
public interface UserMapper {

    @Mapping(source = "email", target = "emailAddress")
    @Mapping(target = "fullName", expression = "java(user.getFirstName() + " " + user.getLastName())")
    UserDTO toDto(User user);

    @Mapping(source = "emailAddress", target = "email")
    @Mapping(target = "createdAt", ignore = true)
    User toEntity(UserDTO dto);

    List<UserDTO> toDtoList(List<User> users);

    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    void updateUserFromDto(UserDTO dto, @MappingTarget User user);
}
3 files · java Explain with highlit

MapStruct generates type-safe bean mappers at compile-time, eliminating manual mapping code. I define mapper interfaces with @Mapper annotation—MapStruct generates implementations. @Mapping annotations handle different property names or custom conversions. The approach is faster than reflection-based mappers like ModelMapper because code generation happens at compile-time. Mappers convert between entities and DTOs, preventing exposure of domain models in APIs. Spring integration uses componentModel = "spring" for dependency injection. Collection mappings work automatically. Custom mapping methods handle complex transformations. MapStruct validates mappings at compile-time, catching errors early. The tool reduces boilerplate while maintaining type safety and performance—essential for clean architecture separating layers.