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.
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.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.