MapStruct

Generated Mappers

MapStruct generates mapper code at compile time from an interface. No reflection at runtime, so it is as fast as hand-written code, and the compiler warns you about fields you forgot to map.

<properties>
    <mapstruct.version>1.6.3</mapstruct.version>
</properties>

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>${mapstruct.version}</version>
</dependency>

<!-- inside maven-compiler-plugin -->
<annotationProcessorPaths>
    <path>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>${mapstruct.version}</version>
    </path>
    <!-- if you use Lombok, add lombok and lombok-mapstruct-binding here too -->
</annotationProcessorPaths>

A MapStruct Mapper

import org.mapstruct.*;

@Mapper(componentModel = "spring")          // generated class becomes a Spring bean
public interface ProductMapper {

    @Mapping(target = "id", ignore = true)
    @Mapping(target = "costPrice", ignore = true)
    @Mapping(target = "createdOn", ignore = true)
    Product toEntity(CreateProductRequest request);

    @Mapping(target = "inStock", expression = "java(product.getStock() > 0)")
    ProductResponse toResponse(Product product);

    List<ProductResponse> toResponses(List<Product> products);

    @Mapping(target = "id", ignore = true)
    @Mapping(target = "costPrice", ignore = true)
    @Mapping(target = "createdOn", ignore = true)
    void update(UpdateProductRequest request, @MappingTarget Product target);
}

// Use it like any bean
@Service
public class ProductService {
    private final ProductMapper mapper;
    public ProductService(ProductMapper mapper) { this.mapper = mapper; }
}

Example

After mvn compile MapStruct writes the implementation for you:

ls target/generated-sources/annotations/com/shopease/product/

Example output

ProductMapperImpl.java

Manual or MapStruct?

Manual mapperMapStruct
SetupNoneDependency + annotation processor
Code to writeEvery field by handOnly the special cases
Forgotten fieldSilent bugCompile-time warning ("Unmapped target property")
Best forSmall apps, a few DTOsMany entities and DTOs

Tip: Add unmappedTargetPolicy = ReportingPolicy.ERROR to @Mapper to turn forgotten fields into build errors.