Backend Development 6 min read

Advanced MapStruct Techniques: expression, qualifiedByName, nullValueMappingStrategy, and Decorator

This article introduces MapStruct, a compile‑time Java bean mapping framework, and demonstrates advanced features such as expression‑based mappings, qualifiedByName custom converters, nullValueMappingStrategy handling, and decorator‑based post‑processing with concrete code examples for Spring‑based projects.

Architect's Guide
Architect's Guide
Architect's Guide
Advanced MapStruct Techniques: expression, qualifiedByName, nullValueMappingStrategy, and Decorator

MapStruct is a compile‑time annotation‑processing framework for Java that automatically generates code to map one bean type to another, offering concise, high‑performance, type‑safe, and IDE‑friendly conversions.

Key features include simplicity, excellent performance (no reflection), safety through compile‑time checks, flexibility via custom conversion methods, and strong IDE support.

expression

Use Java expressions directly in mappings to set target fields, e.g., assigning the current timestamp:

@Mapper(componentModel = "spring")
public interface MyMapper {
    @Mapping(target = "createTime", expression = "java(System.currentTimeMillis())")
    Target toTarget(Source source);
}

The generated implementation sets System.currentTimeMillis() on the createTime field.

qualifiedByName

When default getter/setter mapping is insufficient, qualifiedByName allows custom conversion methods, such as converting a name to uppercase:

@Mapper(componentModel = "spring")
public interface MyMapper {
    @Mapping(target = "name", source = "name", qualifiedByName = "toUpperCase")
    Target toTarget(Source source);

    @Named("toUpperCase")
    default String toUpperCase(String value) {
        return value == null ? null : value.toUpperCase();
    }
}

nullValueMappingStrategy

Control how null source values are mapped. The default RETURN_NULL can be changed to RETURN_DEFAULT to provide empty collections instead of nulls, either at method or class level:

@Mapper(componentModel = "spring",
        nullValueMappingStrategy = org.mapstruct.NullValueMappingStrategy.RETURN_DEFAULT)
public interface MyMapper {
    Target toTarget(Source source);
}

This ensures that when source.ids is null, the generated target.ids becomes an empty list rather than null.

Decorator

A decorator class can wrap generated mapper implementations to apply global post‑processing, such as setting default values for null fields:

public abstract class YourMapperDecorator implements YourMapper {
    private final YourMapper delegate;
    public YourMapperDecorator(YourMapper delegate) { this.delegate = delegate; }
    @Override
    public Target toTarget(Source source) {
        Target result = delegate.toTarget(source);
        if (result != null && result.getField() == null) {
            result.setField("");
        }
        return result;
    }
}

Annotate the mapper interface with @DecoratedWith(YourMapperDecorator.class) so that calls to toTarget are intercepted by the decorator.

Overall, the article provides practical, advanced usage patterns for MapStruct that help developers write cleaner, faster, and safer bean‑mapping code in Java projects.

JavaSpringMapStructannotation-processingBean Mapping
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.