MapStruct Mapper
About
MapStruct is a code generator that simplifies the implementation of mappings between Java bean types based on a convention-over-configuration approach. It is a tool designed to help developers map data from one Java object to another. It is a popular choice for mapping objects, especially in large-scale enterprise applications, due to its performance and ease of use.
Refer to documentation for more details: https://mapstruct.org/documentation/1.5/reference/html/
What is "Convention-Over-Configuration"?
"Convention-over-configuration" is a software design principle used to reduce the number of decisions developers need to make, without sacrificing flexibility. In simpler terms, it means that the framework will assume reasonable default behavior unless the developer specifies otherwise. This approach minimizes the need for extensive configuration by relying on common conventions.
How Does MapStruct Use Convention-Over-Configuration?
MapStruct uses this principle to simplify object mappings by following these conventions
Property Name Matching:
By default, MapStruct maps properties in source and target objects that have the same name and compatible types.
For example, if we have a
UserDTO
class with aname
field and aUserEntity
class with aname
field, MapStruct will automatically mapUserDTO.name
toUserEntity.name
.
Type Matching:
MapStruct can automatically convert between types that have a clear conversion path (e.g.,
String
toint
,Date
toString
).This reduces the need for explicit type conversion configuration.
Default Method Generation:
MapStruct generates implementation code for the mapping methods based on the interface definitions provided by the developer.
For instance, if we define a method
UserDTO toUserDTO(UserEntity entity);
in a mapper interface, MapStruct will generate the implementation for this method, mapping each field based on conventions.
Maven POM Dependency and Plugin
Include the required dependencies in pom.xml file.
It comprises the following artifacts:
org.mapstruct:mapstruct: contains the required annotations such as
@Mapping
org.mapstruct:mapstruct-processor: contains the annotation processor which generates mapper implementations
MapStruct processor options -
Core Features
MapStruct provides a set of core features that allow to map properties between different objects seamlessly. These include:
Basic Type Mapping: MapStruct automatically maps properties with the same name and compatible types.
Handling Null Values: By default, MapStruct maps null values, but we can customize this behavior.
Customizing Mappings with
@Mapping
: This annotation allows to define how individual fields are mapped.
Java Code
Basic Mapping
The @Mapper
annotation causes the MapStruct code generator to create an implementation of the UserMapper
interface during build-time.
When a property has the same name as its target entity counterpart, it will be mapped implicitly.
When a property has a different name in the target entity, its name can be specified via the
@Mapping
annotation.The DTO or the objects being mapped should have getter setter to access fields.
@BeanMapping
with theignoreByDefault
attribute in MapStruct allows us to specify that all properties should be ignored by default, and we can then explicitly specify which properties to include in the mapping. This can be useful for partial updates or when you want to map only a subset of the properties.In some cases, it can be required to manually implement a specific mapping from one type to another which can’t be generated by MapStruct. Use the Default method for such case.
In some cases, we may need mappings which don’t create a new instance of the target type but instead update an existing instance of that type. We can achieve this by adding a parameter for the target object and marking this parameter with
@MappingTarget.
There may be only one parameter marked as mapping target.MapStruct also supports mappings of
public
fields that have no getters/setters. MapStruct will use the fields as read/write accessor if it cannot find suitable getter/setter methods for the property. A field is considered as a read accessor if it ispublic
orpublic final
. If a field isstatic
it is not considered as a read accessor. A field is considered as a write accessor only if it ispublic
. If a field isfinal
and/orstatic
it is not considered as a write accessor.
Using builders
MapStruct also supports mapping of immutable types via builders. When performing a mapping MapStruct checks if there is a builder for the type being mapped. This is done via the BuilderProvider
SPI. If a Builder exists for a certain type, then that builder will be used for the mappings.
Using Constructors
MapStruct supports using constructors for mapping target types. When doing a mapping MapStruct checks if there is a builder for the type being mapped. If there is no builder, then MapStruct looks for a single accessible constructor.
If a constructor is annotated with an annotation named
@Default
it will be used.If a single public constructor exists then it will be used to construct the object, and the other non public constructors will be ignored.
If a parameterless constructor exists then it will be used to construct the object, and the other constructors will be ignored.
If there are multiple eligible constructors then there will be a compilation error due to ambiguous constructors.
Composition Mapping
MapStruct supports the use of meta annotations like @Retention. This allows @Mapping
to be used on other (user defined) annotations for re-use purposes.
For example below. The @ToTransactionHeader
assumes both target beans TransactionEntity
and PaymentEntity
have properties: "id"
, "creationDate"
and "name"
Last updated