Advanced MapStruct Usage: 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 for custom conversions, nullValueMappingStrategy for handling nulls, and the use of Decorator classes to apply global post‑processing logic.
MapStruct is a Java compile‑time annotation‑processing framework that automatically generates code to map one Java bean to another, aiming for minimal code and optimal runtime performance by avoiding reflection.
Key characteristics of MapStruct include concise generated code, excellent performance, type safety, flexibility through custom conversion methods, and strong IDE support.
Expression Mapping
You can execute a Java expression during mapping. For example, the following mapper sets the createTime field of the target object to the current system time:
@Mapper(componentModel = "spring")
public interface MyMapper {
@Mapping(target = "createTime", expression = "java(System.currentTimeMillis())")
Target toTarget(Source source);
}The generated implementation assigns System.currentTimeMillis() to target.setCreateTime .
qualifiedByName
By default, MapStruct copies values using standard getters and setters. When a custom transformation is required—such as converting a string to uppercase—you can use qualifiedByName together with a named method.
@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();
}
}The generated code calls toUpperCase(source.getName()) before setting the target field.
nullValueMappingStrategy
The default strategy NullValueMappingStrategy.RETURN_NULL maps a null source to a null target field. To return a default value—such as an empty list—use NullValueMappingStrategy.RETURN_DEFAULT either at the method or class level.
@Mapper(componentModel = "spring", nullValueMappingStrategy = org.mapstruct.NullValueMappingStrategy.RETURN_DEFAULT)
public interface MyMapper {
Target toTarget(Source source);
}With this strategy, when source.ids is null, the generated mapper creates an empty ArrayList for target.ids instead of leaving it null.
Decorator
A Decorator class can wrap the generated mapper to apply global post‑processing, such as providing 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.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.