当前位置:网站首页>How can attribute mapping of entity classes be without it?
How can attribute mapping of entity classes be without it?
2022-07-02 12:48:00 【Java geek Technology】

We all know , As a project becomes more and more mature , Module division will be more and more detailed , Among them, entity classes generally exist in domain In , but domain It is better not to rely on other projects , Therefore, when other projects want to obtain entity class data, they need to write in their own projects model, Customize model You can map the corresponding entity attributes according to your business needs . thus , This mapping project seems not simple . Ah fan almost got into trouble ……
order
So ah fan is going to give you an Amway product called mapstruct Plug in for , It is specially used to deal with domin Entity classes and model Class attribute mapped , We just need to define mapper Interface ,mapstruct When compiling, it will automatically help us implement this mapping interface , Avoid the trouble of complex mapping implementation .
Then some friends may have to ask ? Why don't BeanUtils Of copyProperties Methods? ? Don't you still realize attribute mapping ?
This one , Fan, I was also curious at first , So it's with BeanUtils We had an in-depth exchange , Only to find out ,BeanUtils It's just a big old man , Can only be mapped to attributes , Or if the properties are the same , Allow fewer object attributes to be mapped ; However, when the mapped attribute data type is modified or the mapped field name is modified , Will cause the mapping to fail . and mapstruct Is a clever daughter-in-law , Her mind is delicate , We have taken into account all the situations we may encounter ( If only ah fan could find such a daughter-in-law , The pig inside laughed )

The following is the open source project address and various examples of this plug-in :
- Github Address :https://github.com/mapstruct/mapstruct/
- Examples of use :https://github.com/mapstruct/mapstruct-examples
One 、 preparation
Next , A fan will go with everyone to untie the real veil of this clever daughter-in-law , So we still need to do some preparatory work .
1.1、 understand @Mapper annotation
from mybatis3.4.0 Started to join @Mapper annotation , The purpose is to stop writing mapper The mapping file .
All we need to do is dao Using annotations on the interface defined by layer sql Statement writing , for example :
@Select("select * from user where name = #{name}")
public User find(String name);
- 1.
- 2.
The above is a simple use , Simple though , But it does show the superiority of this annotation , At least write one less xml file .
But ah fan, I don't want to discuss with you today @Mapper annotation , I mainly want to see my daughter-in-law mapstruct , So I just want to say @Mapper Annotated componentModel attribute ,componentModel Property is used to specify the component type of the automatically generated interface implementation class , This property supports four values :
- default: This is the default ,mapstruct Do not use any component types , Can pass Mappers.getMapper(Class) Method to get the automatically generated instance object .
- cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
- spring: The generated implementation class will automatically add a @Component annotation , Can pass Spring Of @Autowired Way to inject
- jsr330: The generated implementation class will add @javax.inject.Named and @Singleton annotation , Can pass @Inject Annotation access
1.2、 Dependency package
First, you need to import the dependent package , It mainly consists of two packages :
-
org.mapstruct:mapstruct: Contains some necessary comments , for example @Mapping.r If we use JDK Version higher than 1.8, When we're in pom When importing dependencies , The recommended coordinates are :org.mapstruct:mapstruct-jdk8, This can help us make use of some Java8 New features . -
org.mapstruct:mapstruct-processor: Annotation processor , Automatically generated according to annotations mapper The implementation of the .
<dependency>
<groupId>org.mapstruct</groupId>
<!-- jdk8 The following uses mapstruct -->
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
Okay , The preparatory work is done , Next, let's see where Qiao's daughter-in-law is .

Two 、 First, simply play
2.1、 Define entity classes and mapped classes
// Entity class
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
private Integer id;
private String name;
private String createTime;
private LocalDateTime updateTime;
}
// Mapped class VO1: Just like the entity class
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO1 {
private Integer id;
private String name;
private String createTime;
private LocalDateTime updateTime;
}
// Mapped class VO1: One less field than the entity class
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO2 {
private Integer id;
private String name;
private String createTime;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
2.2、 Defining interfaces :
When the attribute of the entity class is the same as that of the mapped object or the attribute value of the mapped object is less :
@Mapper(componentModel = "spring")
public interface UserCovertBasic {
UserCovertBasic INSTANCE = Mappers.getMapper(UserCovertBasic.class);
/**
* The number of fields is the same as the number of types , utilize an instrument BeanUtils A similar effect can be achieved
* @param source
* @return
*/
UserVO1 toConvertVO1(User source);
User fromConvertEntity1(UserVO1 userVO1);
/**
* The number and type of fields are the same , The number of less : It can only convert more into less , So there is no fromConvertEntity2
* @param source
* @return
*/
UserVO2 toConvertVO2(User source);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
As you can see from the code above : Interface declares a member variable INSTANCE, The mother is to allow clients to access Mapper Interface implementation .
2.3、 Use
@RestController
public class TestController {
@GetMapping("convert")
public Object convertEntity() {
User user = User.builder()
.id(1)
.name(" Zhang San ")
.createTime("2020-04-01 11:05:07")
.updateTime(LocalDateTime.now())
.build();
List<Object> objectList = new ArrayList<>();
objectList.add(user);
// Use mapstruct
UserVO1 userVO1 = UserCovertBasic.INSTANCE.toConvertVO1(user);
objectList.add("userVO1:" + UserCovertBasic.INSTANCE.toConvertVO1(user));
objectList.add("userVO1 Convert back to entity class user:" + UserCovertBasic.INSTANCE.fromConvertEntity1(userVO1));
// Output conversion result
objectList.add("userVO2:" + " | " + UserCovertBasic.INSTANCE.toConvertVO2(user));
// Use BeanUtils
UserVO2 userVO22 = new UserVO2();
BeanUtils.copyProperties(user, userVO22);
objectList.add("userVO22:" + " | " + userVO22);
return objectList;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
2.4、 View the compilation results
adopt IDE The decompile function of view automatically generated after compilation UserCovertBasic Implementation class of UserCovertBasicImpl , The contents are as follows :
@Component
public class UserCovertBasicImpl implements UserCovertBasic {
public UserCovertBasicImpl() {
}
public UserVO1 toConvertVO1(User source) {
if (source == null) {
return null;
} else {
UserVO1 userVO1 = new UserVO1();
userVO1.setId(source.getId());
userVO1.setName(source.getName());
userVO1.setCreateTime(source.getCreateTime());
userVO1.setUpdateTime(source.getUpdateTime());
return userVO1;
}
}
public User fromConvertEntity1(UserVO1 userVO1) {
if (userVO1 == null) {
return null;
} else {
User user = new User();
user.setId(userVO1.getId());
user.setName(userVO1.getName());
user.setCreateTime(userVO1.getCreateTime());
user.setUpdateTime(userVO1.getUpdateTime());
return user;
}
}
public UserVO2 toConvertVO2(User source) {
if (source == null) {
return null;
} else {
UserVO2 userVO2 = new UserVO2();
userVO2.setId(source.getId());
userVO2.setName(source.getName());
userVO2.setCreateTime(source.getCreateTime());
return userVO2;
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
2.5、 Browser view results

Okay , One process is over , Does it feel simple to steal ?
What's more , A fan warm reminder : If you want to convert a set , Just replace the entity classes here with collections , for example :
List<UserVO1> toConvertVOList(List<User> source);
- 1.

3、 ... and 、 Not a simple situation
The whole process has been explained above , I'm sure you're right mapstruct Also have a basic understanding , So we won't show all the code in the next situation , After all, the space is limited , So go directly to the key code ( Because the unimportant is the same as the above , ha-ha )
3.1、 Different types
We still use entity classes User; Mapped object UserVO3 Change it to :
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO3 {
private String id;
private String name;
// The attribute of entity class is String
private LocalDateTime createTime;
// The attribute of entity class is LocalDateTime
private String updateTime;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
Then the interface we defined needs to be slightly modified :
@Mappings({
@Mapping(target = "createTime", expression = "java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),
})
UserVO3 toConvertVO3(User source);
User fromConvertEntity3(UserVO3 userVO3);
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
above expression The content of the specified expression is as follows :
public class DateTransform {
public static LocalDateTime strToDate(String str){
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm:ss");
return LocalDateTime.parse("2018-01-12 17:07:05",df);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
adopt IDE Decompile function to view the compiled implementation class , It turned out to be like this :

We can see from the picture , Compile with expression The expression defined in is for the target field createTime There was a transformation ; Then you'll find updateTime Fields are also automatically transferred from LocalDateTime The type is converted to String type .
A powder summary :
When the field types are inconsistent , The following types are mapstruct Automatic type conversion :
- 1、 Basic types and their corresponding packaging types . here
mapstruct The box will be disassembled and assembled automatically . There is no need for artificial treatment - 2、 Basic types of packaging types and string Between types
In addition to the type conversion, we can specify the conversion by defining an expression .
3.2、 Inconsistent field names
We still use entity classes User; Mapped object UserVO4 Change it to :
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO4 {
// The attribute name of entity class is id
private String userId;
// The attribute name of entity class is name
private String userName;
private String createTime;
private String updateTime;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
Then the interface we defined needs to be slightly modified :
adopt IDE Decompile function to view the compiled implementation class , The compiled result is like this :

A powder summary :
When the field names are inconsistent , By using @Mappings Annotations specify correspondence , After compilation, the assignment of the corresponding field can be realized .
Obviously , mapstruct By reading the field name correspondence we configured , Help us assign them to the corresponding positions , It's pretty good , But this is just excellent , And for the more beautiful ones, please continue to look down :

3.3、 Attributes are enumeration types
We still use UserEnum:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserEnum {
private Integer id;
private String name;
private UserTypeEnum userTypeEnum;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
Mapped object UserVO5 Change it to :
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserVO5 {
private Integer id;
private String name;
private String type;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
The enumeration object is :
@Getter
@AllArgsConstructor
public enum UserTypeEnum {
Java("000", "Java Development Engineer "),
DB("001", " Database administrator "),
LINUX("002", "Linux Operator ");
private String value;
private String title;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
Then the interface we defined is still defined as usual , It will not be affected. It will change if it is enumeration :
@Mapping(source = "userTypeEnum", target = "type")
UserVO5 toConvertVO5(UserEnum source);
UserEnum fromConvertEntity5(UserVO5 userVO5);
- 1.
- 2.
- 3.
- 4.
- 5.
adopt IDE Decompile function to view the compiled implementation class , The compiled result is like this :

Obviously , mapstruct By enumerating the contents of the type , Help us convert enumeration types into strings , And give type assignment , It can be said that caution makes the ten thousand year ship .
It seems that this Qiao daughter-in-law is not only excellent, but also careful ……
All the examples in the article have been uploaded github:https://github.com/mmzsblog/mapstructDemo
< END >
边栏推荐
- 应用LNK306GN-TL 转换器、非隔离电源
- 8 examples of using date commands
- 传感器 ADXL335BCPZ-RL7 3轴 加速度计 符合 RoHS/WEEE
- Js10day (API phased completion, regular expression introduction, custom attributes, filtering sensitive word cases, registration module verification cases)
- spfa AcWing 851. spfa求最短路
- 模数转换器(ADC) ADE7913ARIZ 专为三相电能计量应用而设计
- 百款拿来就能用的网页特效,不来看看吗?
- Deep Copy Event bus
- Interview questions for software testing - a collection of interview questions for large factories in 2022
- 通过反射执行任意类的任意方法
猜你喜欢

架构师必须了解的 5 种最佳软件架构模式

JS10day(api 阶段性完结,正则表达式简介,自定义属性,过滤敏感词案例,注册模块验证案例)

面渣逆袭:MySQL六十六问,两万字+五十图详解!有点六

Why do programmers have the idea that code can run without moving? Is it poisonous? Or what?

Linear DP acwing 897 Longest common subsequence
![2.7 binary tree, post order traversal - [FBI tree]](/img/6b/1ded3632cc69329d7b2762ce47fdbc.jpg)
2.7 binary tree, post order traversal - [FBI tree]

Interval DP acwing 282 Stone merging

bellman-ford AcWing 853. 有边数限制的最短路

spfa AcWing 852. SPFA judgement negative ring

NTMFS4C05NT1G N-CH 30V 11.9A MOS管,PDF
随机推荐
js4day(DOM开始:获取DOM元素内容,修改元素样式,修改表单元素属性,setInterval定时器,轮播图案例)
Direct control PTZ PTZ PTZ PTZ camera debugging (c)
Leetcode - Sword finger offer 37, 38
JS iterator generator asynchronous code processing promise+ generator - > await/async
模块化 CommonJS ES Module
async/await 异步函数
1380. Lucky numbers in the matrix [two-dimensional array, matrix]
Linear DP acwing 898 Number triangle
3 A VTT端接 稳压器 NCP51200MNTXG资料
Typora+docsify quick start
一些突然迸发出的程序思想(模块化处理)
上手报告|今天聊聊腾讯目前在用的微服务架构
ArrayList与LinkedList效率的对比
Redis transaction mechanism implementation process and principle, and use transaction mechanism to prevent inventory oversold
Rust language document Lite (Part 1) - cargo, output, basic syntax, data type, ownership, structure, enumeration and pattern matching
NTMFS4C05NT1G N-CH 30V 11.9A MOS管,PDF
百款拿来就能用的网页特效,不来看看吗?
Leetcode - < dynamic planning special> Jianzhi offer 19, 49, 60
2.7 binary tree, post order traversal - [FBI tree]
Linear DP acwing 899 Edit distance