MapStruct - Yash-777/MyWorld GitHub Wiki
MapStruct is a code generator that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach.
The generated mapping code uses plain method invocations and thus is fast, type-safe and easy to understand.
The following shows how to map two objects using MapStruct. Let's assume we have a class representing cars (e.g. a JPA entity) and an accompanying data transfer object (DTO).
Car.java | CarDto.java |
---|---|
|
|
The mapper interfaceReference Guide
The @Mapper
annotation causes the MapStruct code generator to create an implementation of the CarMapper interface during build-time.
In the generated method implementations all readable properties from the source type (e.g. Car) will be copied into the corresponding property in the target type (e.g. CarDto):
• 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.
@Mapper(componentModel = "spring")
public interface BaseMapper {
default String listToString(List<String> listStr) throws Exception {
if (null == listStr) return null;
String str = new ObjectMapper().writeValueAsString(listStr);
return str;
}
default List<String> stringToList(String str) throws Exception {
if (null == str) return null;
List<String> listString = new ObjectMapper().readValue(str, List.class);
return listString;
}
}
@Mapper(componentModel = "spring", uses = {BaseMapper.class})
public interface CarMapper {
@Mapping(source = "car.numberOfSeats", target = "seatCount")
@Mapping(source = "car.make", target = "manufacturer")
CarDto carToCarDto(Car car);
@Mapping(source = "cardto.seatCount", target = "numberOfSeats")
@Mapping(source = "cardto.manufacturer", target = "make")
Car carDtoToCar(CarDto cardto);
}
mapstruct.defaultComponentModel
• default: the mapper uses no component model, instances are typically retrieved via Mappers#getMapper(Class)
• spring: the generated mapper is a singletonscoped Spring bean and can be retrieved via @Autowired
default example
public class Customer {
private Long id;
private String name;
}
public class CustomerDto {
public Long id;
public String customerName;
}
@Mapper
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper( CustomerMapper.class );
@Mapping(target = "name", source = "customerName")
Customer toCustomer(CustomerDto customerDto);
@InheritInverseConfiguration
CustomerDto fromCustomer(Customer customer);
}
Java Build Path - Sources - select following Mapstruct folders
Generated annotations - target/generated-sources/annotations
@Mapper(
componentModel = org.mapstruct.MappingConstants.ComponentModel.SPRING,
unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE
uses = {BaseMapper.class, GroupMapper.class, MenuMapper.class})
public interface UserMapper {
//@Mapping(target = "password" ,source = "user.password", ignore = true)
@Mapping(target = "version", source = "version", defaultValue = "0")
@Mapping(target = "mailStatus", source = "user.mailStatusFlag")
User entityToModel(com.vorwerk.dspro.entities.User user);
@Mapping(target = "mailStatusFlag", source = "mailStatus")
com.vorwerk.dspro.entities.User modelToEntity(User user);
default Status mapToStatusEnum(int value) { return Status.get(value); }
default Integer mapToInteger(Status status) { return status != null ? status.getId() : null; }
}
Click to expand! (Maven POM.xml build configuration for MapStruct)
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.3.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.3.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.3.Final</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<compilerArg>
-Amapstruct.defaultComponentModel=spring
</compilerArg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
Apache Maven1.5 reference-guide: If you’re using Maven to build your project add the following to your pom.xml
to use MapStruct:
mapstruct-lombok: Shows how to use MapStruct together with Lombok (with both a Maven pom.xml); to build the example project, run either mvn clean install
on the command line
Spring migration:
* org.apache.maven.plugins : maven-compiler-plugin : 3.8.1 -> 3.10.1
* org.projectlombok : lombok : 1.18.22 -> 1.18.30
* org.mapstruct : mapstruct-processor : 1.5.3.Final -> 1.6.3
...
<properties>
<org.mapstruct.version>1.6.3</org.mapstruct.version> <!-- 1.5.3.Final -->
<org.projectlombok.version>1.18.30</org.projectlombok.version> <!-- 1.18.22 -->
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- lombok dependencies should not end up on classpath -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <!-- 3.8.1 / 3.10.1 -->
<configuration>
<source>17</source> <!-- depending on your project 1.8 / 17 -->
<target>17</target> <!-- depending on your project -->
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<!-- other annotation processors -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<!--
-Amapstruct.suppressGeneratorTimestamp=true
-Amapstruct.suppressGeneratorVersionInfoComment=true
-Amapstruct.verbose=true
-->
<compilerArg>
-Amapstruct.defaultComponentModel=spring
</compilerArg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
IDE Support: One of the big advantages of MapStruct is the early feedback on problems with the mapping configuration. To fully leverage this in your IDE, make sure the annotation processor runs with each compilation.
Eclipse - Maven Integration
If you are working with a Maven project, then make sure you have the latest version of the m2e-apt plugin installed, which picks up and applies the annotation processor settings automatically.
For best results, add the following to the pom.xml:
<properties>
<!-- automatically run annotation processors within the incremental compilation -->
<m2e.apt.activation>jdt_apt</m2e.apt.activation>
</properties>