“This is the 25th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

When I happened to see a friend in the project using MapStruct for object mapping transformation, I was curious about what framework this was and what problems it could solve. With these two questions in mind, the following article was written.

Introduction to the

MapStruct is a code generator (code that can generate object-mapping transformations) that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach.

The generated mapping code uses ordinary method calls, making it fast, type-safe, and easy to understand.

Applicable scenario

Multi-tier applications typically need to map between different object models, such as entities and Dtos. Writing such mapping code is a tedious and error-prone task. MapStruct aims to simplify this by automating as much as possible.

Compared to other mapping frameworks, MapStruct generates bean maps at compile time, which ensures high performance, allowing for fast developer feedback and thorough error checking.

Solve beanCopy problem in plain English.

Work time

MapStruct is an annotation processor that plugs into the Java compiler and can be used for command-line builds (Maven, Gradle, and so on) as well as your preferred IDE.

MapStruct uses reasonable defaults, but takes action when configuring or implementing special behavior.

Use case

1. Add dependencies

/ / mapstruct implementation 'org. Mapstruct: mapstruct: 1.4.2. The Final' annotationProcessor 'org. Mapstruct: mapstruct - processor: 1.4.2. The Final'Copy the code

2. Define two classes, a Car class (JPA entity class) and a CarDto class (data transfer class)

These two types are very similar except for the field name of the counting attribute, and the type attribute is a CarType enumeration, and in CarDto it’s a string.

The Car class

public class Car {
 
    private String make;
    private int numberOfSeats;
    private CarType type;
 
    //constructor, getters, setters etc.
}
Copy the code

CarType class definition

public enum CarType {
    SEDAN;
}
Copy the code

CarDto class

public class CarDto {
 
    private String make;
    private int seatCount;
    private String type; 
    
    //constructor, getters, setters etc.
}
Copy the code

2. Create the converter class interface that defines the Car object to be converted to CarDto

@Mapper
public interface CarMapper {
 
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
 
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}
Copy the code

1) the.@mapper annotation marks the interface as a mapping interface and lets the MapStruct processor process it during compilation. The actual mapping method is carToCarDto, whose purpose is the original parameter Car, which is converted to the method that returns the result object CarDto

2). If there are different attribute names in the source object and the target object, we can use the @mapping annotation for Mapping. By default, source and target objects are converted to different type attributes. For example, type data is originally an enumeration and can be automatically converted to a string.

3). Support multiple mapping methods with a single Mapper interface. All of these methods are implemented by the MapStruct framework. We can retrieve an instance of the interface implementation from the Mappers class. Typically we declare an INSTANCE attribute in the interface, providing an INSTANCE that is accessed externally.

Unit testing

@Test
public void shouldMapCarToDto () {
    //given
    Car car = new Car("Morris", 5, CarType.SEDAN);

    //when
    CarDto carDto = CarMapper.INSTANCE.carToCarDto(car);

    //then
    assertThat(carDto).isNotNull();
    assertThat(carDto.getMake()).isEqualTo("Morris");
    assertThat(carDto.getSeatCount()).isEqualTo(5);
    assertThat(carDto.getType()).isEqualTo("SEDAN");
}
Copy the code

We use it is very simple, the result is as follows:

Core summary

MapStruct is similar to Lombok in that it is a plug-in that generates auxiliary code for us at compile time. But MapStruct focuses on BeanCopy and object conversion scenarios.

Let’s take a look, which is our CarMapper implementation class CarMapperImpl, these are the framework during compilation, we generated code.

If we use beanutils.copyProperties to convert objects, we need to use reflection to get the properties, methods, etc. And then we do the assignment. Reflection can solve some general scenarios, but for frequent List copies, the performance is not high. We can take a look at some of the code screenshots of copyProperties below:

Personally, I think the advantage of MapStruct is very obvious, that is, it helps us write a lot less getters and setters to convert objects to each other, and its performance is higher than any kind of attribute replication. The downside is that it slows down program compilation and adds a conversion layer to increase code complexity.

Reference documentation

  • mapstruct.org
  • Github.com/mapstruct/m…