当前位置:网站首页>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 >
边栏推荐
- js4day(DOM开始:获取DOM元素内容,修改元素样式,修改表单元素属性,setInterval定时器,轮播图案例)
- Fluent fluent library encapsulation
- 获取文件版权信息
- 应用LNK306GN-TL 转换器、非隔离电源
- 传感器 ADXL335BCPZ-RL7 3轴 加速度计 符合 RoHS/WEEE
- Linear DP acwing 902 Shortest editing distance
- 基于STM32的OLED 屏幕驱动
- Hash table acwing 840 Simulated hash table
- spfa AcWing 852. spfa判断负环
- [ybtoj advanced training guidance] judgment overflow [error]
猜你喜欢

AI mid stage technology research

JS iterator generator asynchronous code processing promise+ generator - > await/async

防抖 节流

通过反射执行任意类的任意方法

浏览器存储方案

js4day(DOM开始:获取DOM元素内容,修改元素样式,修改表单元素属性,setInterval定时器,轮播图案例)

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

Js7day (event object, event flow, event capture and bubble, prevent event flow, event delegation, student information table cases)

线性DP AcWing 899. 编辑距离

Js1day (input / output syntax, data type, data type conversion, VaR and let differences)
随机推荐
Rust语言文档精简版(上)——cargo、输出、基础语法、数据类型、所有权、结构体、枚举和模式匹配
堆 AcWing 838. 堆排序
1380. Lucky numbers in the matrix [two-dimensional array, matrix]
IPhone 6 plus is listed in Apple's "retro products" list
移动式布局(流式布局)
哈希表 AcWing 840. 模拟散列表
2.6 using recursion and stack - [tower of Hanoi problem]
spfa AcWing 852. spfa判断负环
This "little routine" is set on the dough cake of instant noodles. No wonder programmers are always hungry
浏览器存储方案
Js5day (event monitoring, function assignment to variables, callback function, environment object this, select all, invert selection cases, tab column cases)
BOM DOM
spfa AcWing 851. SPFA finding the shortest path
Js1day (input / output syntax, data type, data type conversion, VaR and let differences)
js 迭代器 生成器 异步代码处理 promise+生成器 -> await/async
染色法判定二分图 AcWing 860. 染色法判定二分图
JDBC prevent SQL injection problems and solutions [preparedstatement]
NTMFS4C05NT1G N-CH 30V 11.9A MOS管,PDF
Direct control PTZ PTZ PTZ PTZ camera debugging (c)
The programmer and the female nurse went on a blind date and spent 360. He packed leftovers and was stunned when he received wechat at night