background

As we all know, the Spring framework provides a well-known class copying tool, BeanUtils, which is simple and convenient to use.

However, the internal implementation of the same name property copy based on runtime reflection is not adequate for the field mapping and high performance runtime scenarios required, so the open source community has derived the following class copy framework

  • MapStruct (build time Mapper implementation)
  • Selma (Mapper implementation generated at compile time)
  • Yangtu222 – BeanUtils (generates copy implementation bytecode for the first time)
  • Mica (first generation of copy implementation bytecode)
  • Hutool (Reflection)

use

At present, the second-generation password management platform adopts the BeanUtil class copy method rewritten by MICA. Overall, the performance can meet the requirements. However, in order to further improve the performance of class conversion during query, the application itself contains Swagger dependency, and Mapstruct dependency package is introduced in swagger. There is no need to introduce new dependencies.

Therefore,, the final consideration is to copy the class in the business scenario into a Mapstruct implementation, thus starting the Mapstruct pit climb road.

Software Package Version

SpringBoot: 2.4.2

SpringCloud: 2020.0.1

Lombok: 1.18.16

Mapstruct: 1.3.1. The Final

New rely on

Because mapstruct needs to automatically generate class transformation implementation according to the defined interface, mapstruct interface processing package needs to be introduced in two ways, one is in the form of Maven plug-in, and the other is in the form of Maven dependency

Maven plugin form (official recommendation)

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1 track of</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
Copy the code

Maven dependency form

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>${mapstruct.version}</version>
</dependency>
Copy the code

Considering the large number of Maven modules on the platform and the complex inter-dependency relationship, the missing plug-in dependency can easily lead to bugs that are difficult to be checked, so the second method is finally adopted to reduce the amount of coding.

New mapping class

/ * * *@authorJia Yang * F@date2021/2/18 12:06 * /
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface OssEntityMapper {

	OssVO ossToOssVO(Oss oss);

	OssDTO ossToOssDto(Oss oss);

	/** * bladeFile to Oss **@param bladeFile
	 * @return* /
	@Mapping(target = "fileName", source = "name")
	Oss bladeFileToOss(BladeFile bladeFile);
}
Copy the code

Adding unit tests

Because mapstruct is used for the first time, unit tests are written to check if the code succeeds

/ * * *@authorJia Yang * F@date2021/2/18 in * /
@Slf4j
@ExtendWith(BladeSpringExtension.class)
@SpringBootTest(classes = ResourceApplication.class)
@BladeBootTest(appName = AppConstant.APPLICATION_RESOURCE_NAME, profile = "test", enableLoader = true)
class OssEntityMapperTest {

	@Autowired
	private OssEntityMapper mapper;

	@Test
	void ossToOssVO(a) {
		Oss oss = new Oss();
		oss.setFileName("filename");
		oss.setLink("link");
		oss.setOriginalName("origin");
		oss.setOssType(OssType.QI_NIU_OSS);
		oss.setIsDeleted(BladeConstant.DB_NOT_DELETED);
		OssVO ossVO = mapper.ossToOssVO(oss);
		assertEquals("filename", ossVO.getFileName());
		assertEquals("link", ossVO.getLink());
		assertEquals("origin", ossVO.getOriginalName());
	}

	@Test
	void ossToOssDto(a) {
		Oss oss = new Oss();
		oss.setFileName("filename");
		oss.setLink("link");
		oss.setOriginalName("origin");
		oss.setOssType(OssType.QI_NIU_OSS);
		oss.setIsDeleted(BladeConstant.DB_NOT_DELETED);
		OssDTO ossDTO = mapper.ossToOssDto(oss);
		assertEquals("filename", ossDTO.getFileName());
		assertEquals("link", ossDTO.getLink());
		assertEquals("origin", ossDTO.getOriginalName());
	}

	@Test
	void bladeFileToOss(a) {
		BladeFile file = new BladeFile();
		file.setName("file");
		file.setLink("link");
		file.setOriginalName("origin");
		Oss oss = mapper.bladeFileToOss(file);
		assertEquals("file", oss.getFileName());
		assertEquals("link", oss.getLink());
		assertEquals("origin", oss.getOriginalName()); }}Copy the code

Compile the results

Compiling result, error reported

This is very strange, this is according to the official website of the simplest way to write, and IDEA also installed mapstruct plug-in, also did not report error, can correctly identify attributes, how to compile failed

Looking at the generated code, there is indeed no property mapping

Climb the pit

Because compiling error, consider the following solution

  1. Remove spring container dependencies and write them as class references. – invalid

  2. Remove attribute mapping, try to compile, can compile, but the generated code does not have the same attribute mapping, will only return null value. – invalid

    @Override
    public Oss bladeFileToOss(BladeFile bladeFile) {
        if ( bladeFile == null ) {
            return null;
        }
    
        Oss oss = new Oss();
    
        return oss;
    }
    Copy the code
  3. After changing the class name, the test passes, but the test still fails several times. Could it be related to the compilation environment?

  4. The same code is tested in a separate project (non-Maven multi-module). — Could it be related to Maven multi-module dependencies?

  5. According to the online search results, the lombok version is too low. After checking, the current Lombok version should meet the minimum version requirements. – invalid

  6. Considering whether there is any conflict with some spring components, a separate maven multi-module engineering test was opened, but the test still failed. — Is it really about Maven?

The solution

Finally, the answer was obtained by submitting an issue consultation to the official warehouse

Lombok s version is too high.

The final issue of lowering lombok versions is resolved.