preface
Work often in a situation is, we need to put the Entity/PO/DTO/VO/do the conversion between QueryParam, solve the problem of this kind of tools are many, such as Orika, BeanUtils, Hutool toolkit, why have a special liking to MapStrucet, used to separate to recommend?
Introduction to the
MapSturct is an annotation processor that generates type-safe, high-performance, and dependent-free Javabeans mapping code
How to understand, for BeanUtils, mapping is mainly achieved by reflection, when there are a large number of copies, means that a large number of reflection is used, relatively low efficiency, even “Alibaba Development Manual” also explicitly mentioned that the use of BeanUtils is not allowed
As we all know, the fastest efficiency is of course handwritten get() and set(), and the development efficiency is also the slowest. While MapStruct is compiled by the compiler to generate conventional methods, we can manually generate get() and set() code for us by writing interfaces and annotations, and the efficiency has been increased by many times
The specific performance tests have already been done and can be found in this article: Performance comparison of five common Bean mapping tools
The sample
Let’s first introduce dependencies on MapStruct
Maven:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2. The Final</version>
</dependency>
Copy the code
Add:
<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.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2. The Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Copy the code
There are two entity classes
@Data
public class Student {
String name;
Integer age;
String idCard;
Date birthDay;
}
Copy the code
@Data
public class StudentVO {
String name;
String birthDay;
String idCard;
Integer studentAge;
}
Copy the code
Scenario 1: Mapping between single objects/batch mapping
Student. age is mapped to StudentVO. StudentAge, and student.idCard doesn’t need to be shown in this query. Student. BirthDay is formatted as a string and passed to studentVO. BidthDay
We just need to create an interface:
@Component
@Mapper(componentModel = "spring")
public interface StudentConverter {
@Mapping(target = "studentAge", source = "age")
@Mapping(target = "idCard", ignore = true)
@Mapping(target = "birthDay", dateFormat = "yyyy-MM-dd HH:mm:ss")
StudentVO studentToStudentVO(Student student);
List<StudentVO> studentToStudentVO(List<Student> students);
}
Copy the code
Use:
@RestController
public class TestController {
@Autowired
private StudentConverter studentConverter;
@GetMapping("/test")
public void beanConvertTest(a) {
Student student = new Student();
student.setName("name");
student.setAge(18);
student.setIdCard("123456");
student.setBirthDay(newDate()); StudentVO studentVO = studentConverter.studentToStudentVO(student); System.out.println(studentVO); List<Student> students = Collections.singletonList(student); List<StudentVO> studentVOS = studentConverter.studentToStudentVO(students); System.out.println(studentVOS); }}Copy the code
Output results:
You can see that the date of birth is successfully formatted into the string that we want, idCard we don’t need so it’s not mapped
Scenario 2: Multiple objects are mapped to one
There may be situations where multiple objects need to be mapped into one object, and multiple objects may have duplicate fields. This can be resolved flexibly according to the @Mapping annotation
Now add a new class address.class where the name field and the student.name field are duplicate fields
@Data
public class Address {
String name;
String address;
}
Copy the code
The requirement is to add the address field to studentvo.class based on scenario 1, but use the name field from student.class.
@Data
public class StudentVO {
String name;
String birthDay;
String idCard;
Integer studentAge;
// Add a new field
String address;
}
Copy the code
We can use the source parameter to set which instance to map the fields from. The interface method is as follows:
@Mapping(target = "studentAge", source = "student.age")
@Mapping(target = "idCard", ignore = true)
@Mapping(target = "birthDay", source = "student.birthDay", dateFormat = "yyyy-MM-dd HH:mm:ss")
@Mapping(target = "name", source = "student.name")
StudentVO studentAndAddressToVO(Student student, Address address);
Copy the code
Use:
@GetMapping("/test")
public void beanConvertTest(a) {
Student student = new Student();
student.setName("name");
student.setAge(18);
student.setIdCard("123456");
student.setBirthDay(new Date());
Address address = new Address();
address.setName("addressName");
address.setAddress("address");
StudentVO studentVO = studentConverter.studentAndAddressToVO(student, address);
System.out.println(studentVO);
}
Copy the code
Output results:
For the above example, it is important to note that when multiple objects are mapped into one object, only duplicate fields or fields with different field names need to be mapped with annotations to tell MapStruct which source field to use
Mapstruct /mapstruct-examples: Examples for using mapstruct (github.com)
Other Notes
- If Lombok is also used in your project, make sure that Lombok’s version is 1.18.10 or higher, or you may fail to compile
- If the interface store package name is mapper, it may conflict with Mybatis and cause the project to fail
- When two object properties are inconsistent, such as
Student
Object does not exist inStudentVO
During compilation, there will be a warning@Mapping
In the configurationignore = true
, when there are many fields, you can directly@Mapper
Set in theunmappedTargetPolicy
Attributes orunmappedSourcePolicy
Properties forReportingPolicy.IGNORE
Can be
Summary: How should I choose an object mapping tool
- If the field is less, write up is not troublesome, there is no need to use the frame, handwritten
get()/set()
Technology should not be used for its own sake, it should be used to solve a problem - If the field is more, the conversion is not frequent, to save trouble
BeanUtils
Yes, slightly more complex scenarios can also be usedHutool toolkittheBeanUtils
, provides more copying options - Fields are many and frequently converted. For performance purposes, choose one of the high-performance tools, such as MapStruct, which is recommended in this article
Reference
Common development library – MapStruct tool library, rounding | Java stack all knowledge system (pdai. Tech)
Throw away those BeanUtils utility classes, MapStruct smells good!! (juejin.cn)