preface

It’s 2021, and you probably haven’t used Lombok yet.

Lombok is a Java plug-in that simplifies and eliminates redundant code in the form of “annotations” that use the Annotation Processor to generate “repetitive” code at compile time. It is also important to note that in the IDEA environment, you need to install an additional Lombok plug-in. (This article does not cover Lombok, but if you want to learn more about Lombok, you can go to the official documentation to learn how to use all of Lombok’s annotations.)

For those of you who are unfamiliar with MapStruct, I’m sure you’ve used something similar. Examples include Apache Commons BeanUtils, Spring BeanUtils, BeanCopier, Dozer, and more. Yes, MapStruct is also intended to address the general need to copy object properties. The traditional method of using reflection to copy attributes has low performance and low efficiency in the scenario of large data volume. The bottom layer of MapStruct uses getter/setter methods to improve property copy performance. Like Lombok, MapStruct uses the Annotation Processor principle to generate code at compile time.

Hit the pit

First we according to MapStruct official document introduction, build a simple chestnut 🌰~

Introducing dependencies:

<properties>
    <mapstruct.version>1.4.2. The Final</mapstruct.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${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>
                    <! -- MapStruct generates code from this plugin when compiled -->
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
Copy the code

Create two classes for property copies.

/ / the source object
public class CarDO {
    private String make;
    private int numberOfSeats;
    private CarType type;

    public CarDO(a) {}public CarDO(String make, int numberOfSeats, CarType type) {
        this.make = make;
        this.numberOfSeats = numberOfSeats;
        this.type = type;
    }

    public String getMake(a) {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getNumberOfSeats(a) {
        return numberOfSeats;
    }

    public void setNumberOfSeats(int numberOfSeats) {
        this.numberOfSeats = numberOfSeats;
    }

    public CarType getType(a) {
        return type;
    }

    public void setType(CarType type) {
        this.type = type; }}// Test enumeration
public enum CarType {
    /** * common */
    COMMON,
    /** ** ** */
    OLD,
    /** ** ** /
    SPORTS;
}

// Target object
public class CarDTO {
    private String make;
    private int seatCount;
    private String type;

    public CarDTO(a) {}public CarDTO(String make, int seatCount, String type) {
        this.make = make;
        this.seatCount = seatCount;
        this.type = type;
    }

    public String getMake(a) {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getSeatCount(a) {
        return seatCount;
    }

    public void setSeatCount(int seatCount) {
        this.seatCount = seatCount;
    }

    public String getType(a) {
        return type;
    }

    public void setType(String type) {
        this.type = type; }}Copy the code

Create an object copy interface that tells MapStruct which object’s property copy needs to be generated.

Note: here @mapper/Mappers / @mapping are all under the org.mapstruct package, don’t misquote ~ when used with Mybatis

@Mapper
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDTO carToCarDto(CarDO car);
}
Copy the code

Finally, create a test class and test it!

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

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

        //then
        Assert.assertNotNull(carDto);
        Assert.assertEquals("Morris", carDto.getMake());
        Assert.assertEquals(5, carDto.getSeatCount());
        Assert.assertEquals("SPORTS", carDto.getType()); }}Copy the code

According to the practice of official documents, very smooth, the test passed!

What happens if we replace the getters/setters in our two entity classes with Lombok?

Let’s start by modifying the Pom.xml file to add Lombok dependencies:

<properties>
+ < lombok. Version > 1.18.12 < / lombok version >< mapstruct version > 1.4.2. Final < / mapstruct version > < / properties > < dependencies >+ 
      
+ 
      
       org.projectlombok
      
+ 
      
       lombok
      
+ 
      
       ${lombok.version}
      
+ <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version>  </dependency> </dependencies>Copy the code

At this point, our entity class code should look like this:

/ / the source object
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CarDO {
    private String make;
    private int numberOfSeats;
    private CarType type;
}

// Target object
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CarDTO {
    private String make;
    private int seatCount;
    private String type;
}
Copy the code

If you run the test class again, you will get an error like “Java: symbol not found symbol: method getXXX()” at compile time, as shown below:

When this happens, Lombok is clearly not working, so how do you fix it?

Solutions of the pit

Remember at the beginning of this article that Lombok and MapStruct both use the Annotation Processor to generate code at compile time?

Knowing the principle, the problem will be easily solved.

Earlier, when we tested MapStruct, we added a plug-in to the pom.xml file to tell Maven that MapStruct code generation logic needs to be performed at compile time, but we did not tell Maven that Lombok also needs to generate code at compile time.

We add this paragraph to the build node of the pom.xml file:

<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> <! Lombok generates code from this plug-in at compile time -->+ 
      
+ 
      
       org.projectlombok
      
+ 
      
       lombok
      
+ 
      
       ${lombok.version}
      
+ <! <path> <groupId>org. MapStruct </groupId> <artifactId> MapStruct processor</artifactId> <version>${mapstruct.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>Copy the code

You can’t find the get method by running the test class


Created at: 2021-04-22 14:01:21

Original link: xkcoding.com/2021/04/22/…

Supporting code: github.com/xkcoding/pr…