An Introduction to MapStruct: Java Bean Mapping, Usage, and Best Practices
This article explains what MapStruct is, how to set it up in a Java project, demonstrates various mapping scenarios—including simple, nested, custom, and multi‑source mappings—covers performance benefits, integration methods, and provides complete code examples for practical backend development.
1. What is MapStruct
MapStruct is a compile‑time annotation processor that generates type‑safe, high‑performance, dependency‑free Java bean mapping code, solving the common pain of manual bean conversion and reflection‑based utilities.
2. Getting Started
To use MapStruct, add the required Maven dependencies (lombok, mapstruct, mapstruct‑processor, hutool, junit) to your project.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
... (other dependencies omitted for brevity)Define your source POJO and target DTO, both annotated with @Data (Lombok) and containing the fields to be mapped.
@Data
public class User {
private Integer id;
private String name;
private String address;
private Date birth;
}
@Data
public class UserDto implements Serializable {
private Integer id;
private String name;
private String address;
private Date birth;
}Create a mapper interface annotated with @Mapper and declare mapping methods. For simple one‑to‑one mapping MapStruct generates the implementation automatically.
@Mapper
public interface UserMapper {
UserDto userToUserDto(User user);
List
userToUserDto(List
users);
}A JUnit test shows how to obtain the mapper via Mappers.getMapper(UserMapper.class) and perform the conversion.
@Test
public void userPoToUserDto() {
User user = new User();
user.setId(1);
user.setName("myx");
user.setAddress("河北沧州");
user.setBirth(new Date());
UserMapper mapper = Mappers.getMapper(UserMapper.class);
UserDto userDto = mapper.userToUserDto(user);
System.out.println(userDto);
}3. Advantages of MapStruct
High performance compared with reflection‑based utilities.
Simple usage – declare an interface and let MapStruct generate the code.
Generated code has no runtime dependencies.
Easy to debug because the source code is visible.
4. Usage Scenarios
Various examples illustrate how to handle different mapping requirements:
Same property names : automatic mapping.
Different property names : use @Mapping(source = "pwd", target = "password") .
Nested objects and collections : MapStruct recursively maps nested beans and lists.
Custom conversion logic : define default methods in the mapper interface (Java 8+).
Multi‑source mapping : map from several source parameters to one target.
Updating existing beans : use @MappingTarget to modify a target instance.
Map mapping : convert Map to Map with @MapMapping .
Deeply nested structures : MapStruct can map multi‑level objects, either by defining individual methods or by using the uses attribute to delegate to other mappers.
Custom type conversion (e.g., Boolean ↔ String) can be achieved by providing a helper class and referencing it via @Mapper(uses = {BooleanStrFormat.class}) .
5. Obtaining a Mapper
Factory method: Mappers.getMapper(MyMapper.class) .
Define a static INSTANCE field in the interface for convenient access.
Dependency injection: configure @Mapper(componentModel = "spring") (or "cdi") and let the framework inject the mapper.
Injection strategy can be FIELD (default) or CONSTRUCTOR .
6. Conclusion
The article encourages readers to like, share, and follow the author’s public account for more technical content.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.