"MapStruct" POJO mapping conversion framework guide

Preface

This article will mainly explain the mutual conversion methods of VO, DTO and Entity in back-end development, and target themThe relatively mature framework MapStruct is used for interpretation and teaching

download

question

Under the microservice architecture, service splitting will produce three types of POJOs: VO, DTO, and Entity

  • VO is used for front-end interface parameter transfer, for example, it is used for http interface to receive request parameters. You can inherit and extend DTO, or use DTO directly
  • DTO is used for rpc interface parameter passing. Define it separately, or inherit DTO that extends other rpc interfaces
  • Entity (PO) is used for orm mapping processing, corresponding to the table structure, and is only used internally within the service and cannot be used externally

Note: For an explanation of POJO, please see the Supplementary chapter at the end of the article

The microservice architecture is oriented to POJO definitions in different scenarios and introducesfront-end request processing issues, that is, Conversion between the three:

  • Request: VO => DTO => Entity
  • Return: Entity => DTO => VO

structure

Entity

@Data
@TableName(value = "orders", schema = "crazy1984")
public class Order {
    
    
    @TableId(type = IdType.AUTO)
    private int id;
    private String orderId;
    private String orderType;
    private int orderStatus;
    private Date createdAt;
    private Date updatedAt;
}

DTO

@Data
public class OrderDTO {
    
    
    private String orderId;
    private String orderType;
    private int orderStatus;
    private Date createdAt;
}

VO

@Data
public class OrderVO extends OrderDTO{
    
    
    private String orderTypeName;
    private String orderStatusName;
}

Manual conversion

We can use the most direct method to copy POJO attributes one by one through code

But this method is tooinefficient and adds a lot of inefficient duplication of work to developers. , also difficult to maintain (for example, when adding a new field, all relevant parts must be modified simultaneously)

OrderDTO dto = new OrderDTO();
dto.setOrderId(entity.getOrderId());
dto.setOrderType(entity.getOrderType());
dto.setOrderStatus(entity.getOrderStatus());
dto.setCreatedAt(entity.getCreatedAt());

Tool class conversion

The improvement method is to use tool class to automatically copy properties with the same name, such as using Spring's BeanUtils

OrderDTO dto = new OrderDTO();
BeanUtils.copyProperties(entity, dto);

This can save a lot of work, but it will bring the following shortcomings:

  • Attribute name mapping is not supported, attribute names must be exactly the same
  • Automatic type conversion is not supported, Spring's BeanUtils requires that the types of source properties and target properties are mutually assignable
  • The performance loss is large. The attribute name matching, type check, and write permission check in the attribute copy are all dynamic judgments, and there is a performance loss

In addition, there are many tools. The following picture showsa comparison of various tools:

copy tool Usage efficiency
Spring BeanUtils Easy to use, moderately efficient
Cglib BeanCopier Easy to use and most efficient
Apache BeanUtils Easy to use, but low in efficiency. The reason is that the tool has done a lot of verification, compatibility, log printing, etc., resulting in performance degradation (The use of this tool is prohibited in the Alibaba constraint specifications a>)
Apache PropertyUtils Easy to use, low efficiency
Hutool BeanUtil Easy to use, perfect packaging, high efficiency

Mapping frame conversion

There are currently many open source and mature mapping frameworks:

The above frameworks all supportmapping of different attribute names, automatic type conversion< a i=4>,Recursively map custom object properties

The implementation principle isbased on the reflection mechanism, which implements get and set calls of class attributes,based on annotations , configuration to achieve mapping and type conversion of different attribute names

Framework performance comparison, MapStruct and JMapper have better performance . Because theirmapping process is static, the actual performance is the same as handwriting get and set

And during the development process, the generated code can be checked to ensure that there are no errors in the mapping conversion, which is more reliable than the black box implementation of ModelMapper. It can also support the mutual conversion between grpc protocol protobuf objects and entities.

Below we will explain in detail MapStruct the use of the framework

MapStruct

Introduction

官方仓库:mapstruct/mapstruct: An annotation processor for generating type-safe bean mappers (github.com)

官方文档:MapStruct – Java bean mappings, the easy way!

MapStruct is a code generator,based on convention rather than configuration, which greatly simplifies the implementation of mapping between Java Bean types

Install

Official documentation:Installation – MapStruct

First we need to add the following content to pom.xml

Note: This article uses Maven as an example. Gradle users can refer to the official documentation above.

...
<properties>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</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> <!-- depending on your project -->
                <target>1.8</target> <!-- depending on your project -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                    <!-- other annotation processors -->
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

Example

Official example code:mapstruct-examples/mapstruct-mapper-repo at main · mapstruct/mapstruct-examples (github.com)

We can directly download the project folder corresponding to the demo above separately. For specific methods, please refer to the Supplementary chapter at the end of the article

You can also create a Spring project by yourself, then install MapStruct in sequence and create the following file

Car.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
    
    

    private String make;
    private int numberOfSeats;
    private CarType type;
    
}

CarType.java

public enum CarType {
    
    
    SPORTS, OTHER;
}

CarDto.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CarDto {
    
    

    private String make;
    private int seatCount;
    private String type;

}

CarMapper.java

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

TestMapperRepo.java

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

        //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("SPORTS");
    }
}

But MapStruct conflicts with Lombok by default and cannot be recognized. There will beattribute not found error. You can Lombok comments are replaced with corresponding codes, or pom.xml is replaced as follows

<properties>
    <org.projectlombok.version>1.18.16</org.projectlombok.version>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
    <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${org.projectlombok.version}</version>
    </dependency>

    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</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>${org.projectlombok.version}</version>
                    </path>
                    <!-- This is needed when using Lombok 1.18.16 and above -->
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok-mapstruct-binding</artifactId>
                        <version>${lombok-mapstruct-binding.version}</version>
                    </path>
                    <!-- Mapstruct should follow the lombok path(s) -->
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

We need to ensure that the minimum version of Lombok is 1.18.16, and in the annotationProcessorPaths, the configuration of mapstruct-processor must be after lombok

Replenish

POJO

POJO vs Java Beans - GeeksforGeeks

Introduction

POJO (Plain Old Java Object) literally translates as "Plain Old Java Object", but its more popular name is " Simple Java Object

Intrinsic meaning:A Java object that does not inherit or implement any other Java framework’s classes or interfaces, and is not invaded by other frameworks a>

Note: The classes and interfaces inside only refer to classes and interfaces in other Java frameworks, not all classes and interfaces

Related Links:

Convert object

We can help understand POJO is an intermediate object

This intermediate object can be converted into PO, DTO, VO according to different situations

1 . POJO Persistentafter --> PO(Persistent Object)< /span>

2 . POJO 传输过程中 --> DTO(Data Transfer Object)

3 . POJO operationDisplay layer --> VO (View Object)

4 . POJO operationBusiness Object )

Note: BO’s main function is to encapsulate business logic into objects, This object can include one or more other objects , BO By calling the DAO method, combined PO, VO conduct business operations

GitHub separate download folder

Needless to say, there is no need to say more about downloading files separately. After we click to enter the file on GitHub, there will be a raw file download button in the upper right corner. Click to download the source file.

If you are downloading a folder, there are the following methods

GitZip

Download Google Plugin GitZip

Link:GitZip for github - Chrome App Store (google.com)

After installation, we double-click the corresponding folder and then click the download button in the lower right corner to download.

image-20231104112214588

DownGit

Website address:DownGit (minhaskamal.github.io)

Reference link

This article is published by the blog post platform OpenWrite!

Guess you like

Origin blog.csdn.net/m0_63748493/article/details/134241205