MapStruct

Language: Java

CLI/Utils

MapStruct was created to eliminate the boilerplate code of writing manual mapping logic between Java objects. By generating mapper implementations at compile-time, it ensures type safety, high performance, and easy maintenance.

MapStruct is a Java annotation processor for generating type-safe and performant mappers that automatically convert between Java beans (DTOs and entities).

Installation

maven: Add org.mapstruct:mapstruct dependency and mapstruct-processor annotationProcessor in pom.xml
gradle: Add implementation 'org.mapstruct:mapstruct:1.6.14.Final' and annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.14.Final' in build.gradle

Usage

MapStruct allows developers to define mapper interfaces annotated with `@Mapper`. At compile-time, MapStruct generates the implementation class for converting between source and target objects.

Defining a simple mapper

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    UserDTO userToUserDTO(User user);
}

Defines a mapper interface for converting a `User` entity to `UserDTO`. MapStruct generates the implementation automatically.

Using the mapper

User user = new User(1, "Alice", "alice@example.com");
UserDTO dto = UserMapper.INSTANCE.userToUserDTO(user);
System.out.println(dto.getName());

Uses the generated mapper to convert a `User` object to a `UserDTO` object.

Mapping collections

List<UserDTO> dtos = UserMapper.INSTANCE.usersToUserDTOs(usersList);

MapStruct can convert collections of objects automatically.

Custom field mapping

@Mapping(source = "email", target = "contactEmail")
UserDTO userToUserDTO(User user);

Maps fields with different names using `@Mapping` annotation.

Nested object mapping

@Mapping(source = "address.street", target = "streetName")
UserDTO userToUserDTO(User user);

Maps nested fields from source object to target object.

Mapping with expressions

@Mapping(target = "fullName", expression = "java(user.getFirstName() + ' ' + user.getLastName())")
UserDTO userToUserDTO(User user);

Uses Java expressions for complex field transformations during mapping.

Error Handling

UnmappedTargetPropertyException: Occurs when a target field does not have a corresponding mapping. Add `@Mapping` or `@Mappings` annotations or ignore unmapped fields.
AnnotationProcessingException: Occurs if MapStruct annotation processor is not configured correctly. Ensure proper dependencies and annotationProcessor setup.
IncompatibleTypesException: Occurs when source and target types cannot be mapped. Use type conversions or custom mapping methods.

Best Practices

Keep mapping interfaces simple and modular.

Use `@Mapper` with componentModel = 'spring' for Spring Boot integration.

Prefer compile-time mappings over reflection-based mapping for performance.

Leverage `@Mapping` for fields with different names or types.

Validate mapping results in unit tests to ensure correctness.