MapStruct — An Entity Mapping Solution

Tushar Sharma
Oct 18, 2018 · 3 min read

Tired of writing the code for mapping beans to entities and vice versa over and over again? Here comes MapStruct to the rescue!

MapStruct in a line is a code generator that simplifies bean mappings.

Let’s get straight down to the nitty-gritty details! The example assumes we are using Spring Boot with maven.

First, we begin with adding the dependencies to the pom.xml file

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.1.0.Final</version>
</dependency>

MapStruct also requires a processor plugin to be added to pom.xml. The mapstruct-processor is used to generate the mapper implementation during the build phase.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1 </version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.1.0.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

Now we move on the process of creating a mapper interface for our bean and entity.

We create a simple entity:

@Entity
public class Employee{
private Long empId;
private String name;
//Getter Setter omitted for brevity
}

Then we create a simple Data Transfer Object(DTO):

public class EmployeeDTO {
private Long empId;
private String name;
//Getter Setter omitted for brevity
}

We then create a mapper interface for the mappings:

@Mapper(componentModel="spring")
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
EmployeeDTO employeeToEmployeeDTO(Employee entity);
Employee employeeDTOToEmployee(EmployeeDTO dto);
}

The componentModel is utilized for Spring’s IoC, for the Mapper to be found and instantiated as a bean.The INSTANCE is created to use the mapper methods.

We can generate the mapper by running the mvn:clean install command

The generated mapper can be found under target > generated sources>package hierarchy

We can use the mapper as follows :

EmployeeDTO temp =  
EmployeeMapper.INSTANCE.employeeToEmployeeDTO(entity);

Now that the basic mapper usage is out of the way, let’s check out some specific use cases:

  1. The source and target member names are different:
@Mapper(componentModel="spring")
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
@Mappings({
@Mapping(target="employeeName", source="entity.name")
})
EmployeeDTO employeeToEmployeeDTO(Employee entity);
@Mappings({
@Mapping(target="name", source="dto.employeeName")
})
Employee employeeDTOToEmployee(EmployeeDTO dto);
}

The above code assumes the DTO has the field employeeName and the entity has the field name.
The @Mappings & @Mapping annotation is used to specify target and source for mapping if their names are different.

2. Entity is composite and has another object inside it which needs a mapper of itself

@Entity
public class Employee{
private Long empId;
private String name;
private Department dept; // another entity
//Getter Setter omitted for brevity
}
@Entity
public class Department{
private Long deptId;
private String name;
//Getter Setter omitted for brevity
}
------------------------------------------------------------------
public class EmployeeDTO {
private Long empId;
private String name;
private DepartmentDTO dept;
//Getter Setter omitted for brevity
}
public class DepartmentDTO{
private Long deptId;
private String name;
//Getter Setter omitted for brevity
}

The mapper will be defined as:

@Mapper(componentModel="spring")
public interface OrgMapper {
OrgMapper INSTANCE = Mappers.getMapper(OrgMapper.class);
@Mappings({
@Mapping(target="employeeName", source="entity.name")
})
EmployeeDTO employeeToEmployeeDTO(Employee entity);
@Mappings({
@Mapping(target="name", source="dto.employeeName")
})
Employee employeeDTOToEmployee(EmployeeDTO dto);
}
//Department mapper
DepartmentDTO departmentToDepartmentDTO(department entity);
Department departmentDTOToDepartment(DepartmentDTO assetsDTO);
}

By defining the mappers of the contained class here, MapStruct automatically includes it in while creating the mapper code. A similar structure can be used in case of multiple classes within a class.
Another way of doing this if you want to segregate your mappers for different entities is :

@Mapper(componentModel="spring",uses=DepartmentMapper.class)
public interface EmployeeMapper {
EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);
@Mappings({
@Mapping(target="employeeName", source="entity.name")
})
EmployeeDTO employeeToEmployeeDTO(Employee entity);
@Mappings({
@Mapping(target="name", source="dto.employeeName")
})
Employee employeeDTOToEmployee(EmployeeDTO dto);
}
@Mapper(componentModel="spring")
public interface DepartmentMapper{
DepartmentMapper INSTANCE =
Mappers.getMapper(DepartmentMapper.class);
DepartmentDTO departmentToDepartmentDTO(department entity);
Department departmentDTOToDepartment(DepartmentDTO assetsDTO);
}

The uses attribute is used to specify other mappers the given mapper needs, it can be used to specify multiple mappers too, within curly braces {}.

Hope this helps someone beginning out their journey with MapStruct. That’s all folks! These were the use cases i encountered in my ongoing skirmish with MapStruct! Stay tuned for more!

Tushar Sharma

Written by

An avid reader and voracious consumer of knowledge. Striving to be better every day. Knows some tech stuff too you know!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade