Introduction to MapStruct: What It Is, How to Use It, and Its Advantages
This article introduces MapStruct, a type‑safe, high‑performance, dependency‑free Java bean mapping annotation processor, explains the problems with manual and reflection‑based conversions, provides step‑by‑step Maven setup, entity/DTO definitions, mapper interface, and a JUnit test, and discusses its performance, debugging, and simplicity advantages.
When I first encountered MapStruct I was thrilled because it matched my desire for a clean, compile‑time solution to JavaBean conversion.
1. What is MapStruct?
1.1 The JavaBean Conversion Problem
Converting between JavaBeans often requires verbose code, reflection, or utilities such as BeanUtils or BeanCopier , which can hurt performance and demand identical field names.
Reflection‑based approaches are convenient but slower, while manual setters are error‑prone and time‑consuming.
1.2 What MapStruct Brings
MapStruct is a compile‑time annotation processor that generates type‑safe, high‑performance, dependency‑free mapping code.
Annotation processor
Generates mapping code for JavaBeans
Ensures type safety, high performance, and no runtime dependencies
It lets developers define mappings via annotations, reducing boilerplate and mistakes.
2. Getting Started with MapStruct
The example uses Maven for dependency management.
2.1 Adding Dependencies
<properties>
<org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>2.2 Defining Entity and DTO
Sample Order entity and OrderQueryParam DTO are shown below.
@Data
public class Order {
private Long id;
private String orderSn;
private String receiverKeyword;
private Integer status;
private Integer orderType;
private Integer sourceType;
} @Data
public class OrderQueryParam {
private String orderSn;
private String receiverKeyword;
private Integer status;
private Integer orderType;
private Integer sourceType;
}2.3 Writing the Mapper
The mapper interface is annotated with @Mapper and declares the conversion method.
import com.homejim.mapstruct.dto.OrderQueryParam;
import com.homejim.mapstruct.entity.Order;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface OrderMapper {
OrderQueryParam entity2queryParam(Order order);
}2.4 Testing the Mapping
@Test
public void entity2queryParam() {
Order order = new Order();
order.setId(12345L);
order.setOrderSn("orderSn");
order.setOrderType(0);
order.setReceiverKeyword("keyword");
order.setSourceType(1);
order.setStatus(2);
OrderMapper mapper = Mappers.getMapper(OrderMapper.class);
OrderQueryParam param = mapper.entity2queryParam(order);
assertEquals(param.getOrderSn(), order.getOrderSn());
assertEquals(param.getOrderType(), order.getOrderType());
assertEquals(param.getReceiverKeyword(), order.getReceiverKeyword());
assertEquals(param.getSourceType(), order.getSourceType());
assertEquals(param.getStatus(), order.getStatus());
}3. Analysis of MapStruct
3.1 High Performance
Unlike reflection, the generated code runs as fast as hand‑written code because it is compiled directly.
3.2 Easy Debugging
The generated implementation (found under target/generated-sources/annotations ) can be inspected and stepped through in a debugger.
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-08-02T00:29:49+0800",
comments = "version: 1.3.0.Final, compiler: javac, environment: Java 11.0.2 (Oracle Corporation)"
)
public class OrderMapperImpl implements OrderMapper {
@Override
public OrderQueryParam entity2queryParam(Order order) {
if (order == null) {
return null;
}
OrderQueryParam param = new OrderQueryParam();
param.setOrderSn(order.getOrderSn());
param.setReceiverKeyword(order.getReceiverKeyword());
param.setStatus(order.getStatus());
param.setOrderType(order.getOrderType());
param.setSourceType(order.getSourceType());
return param;
}
}3.3 Simplicity
For straightforward mappings, simply declaring the interface is enough; special cases can be handled with additional annotations.
3.4 No Runtime Dependency
The generated code is independent and does not require MapStruct at runtime.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.