MapStruct is a powerful mapping library in Java. However, some of its behaviors can be non-obvious, especially when it comes to null handling and configuration.
Below are some common areas MapStruct users should be aware of.
Null Checks
Official documentation: Null Check Strategies .
NullValueCheckStrategy.ON_IMPLICIT_CONVERSION
The default NullValueCheckStrategy
is ON_IMPLICIT_CONVERSION
. This means MapStruct will insert a null check only if a type conversion is involved—e.g., mapping an Integer
to a String
.
// With type conversion
// Given input.count is an Integer and output.count is a String,
// a null check would be performed first.
if (input.getCount() != null) {
output.setCount(String.valueOf(input.getCount()));
}
// Without type conversion
// When both input.name and output.name are Strings, it maps directly.
output.setName(input.getName());
NullValueCheckStrategy.ALWAYS
With NullValueCheckStrategy.ALWAYS
, MapStruct always adds a null check for non-primitive source properties—unless a presence checker is defined on the source bean.
However, this strategy comes with a few important caveats:
-
qualifiedByName()
method won’t be called if the input is nullpublic abstract class MovieMapper { @Mapping(target = "category", source = "movie", qualifiedByName = "categoryToString") public abstract GermanRelease toGerman(Movie movie); @Named("categoryToString") public String categoryToString(Movie movie) { // Some mapping logic } } // Generated code: if (movie != null) { output.setCategory(categoryToString(movie)); }
If movie is null, the categoryToString method is not invoked.
-
expression
mappings are not affectedpublic abstract class MovieMapper { @Mapping(target = "category", expression = "java(movie.getCategory() != null ? movie.getCategory() : null)") public abstract GermanRelease toGerman(Movie movie); protected String categoryToString(Movie movie) { // Some mapping logic } } // Generated code: output.setCategory(movie.getCategory() != null ? movie.getCategory() : null);
Expression-based mappings are inlined directly and aren’t skipped based on null checks for the source.
Deprecation of org.mapstruct.ap.spi.BuilderProvider
The SPI configuration via org.mapstruct.ap.spi.BuilderProvider
(under META-INF/services
) has stopped working since MapStruct 1.5.5.Final
.
Refer to mapstruct#1661 and commit 5f4d3558 for details.
To disable builder usage, use the processor option mapstruct.disableBuilders during compilation.
A Stack Overflow answer shows how to do this with Gradle. Here’s how you can do it with Maven:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<compilerArg>
-Amapstruct.disableBuilders=true <!-- Disable builder by default for Lombok compatibility -->
</compilerArg>
</compilerArgs>
</configuration>
</plugin>
This can help avoid compatibility issues with libraries like Lombok.
Tip: Instead of disabling builders globally, consider disabling them at the mapper level for more transparency and control.