介绍
在业务项目的开发中,我们经常需要将Java对象进行转换,比如从外部HSF服务得到的对象转换为本域的业务对象domain object,将domain object转为数据持久层的data object,将domain object 转换为DTO以便返回给外部调用方等。在转换时大部分属性都是相同的,只有少部分的不同,如果手工编写转换代码,会很繁琐。这时我们可以通过一些对象转换框架来更方便的做这件事情。
这样的对象转换框架有不少,比较有名的有ModelMapper和MapStruct。它们所使用的实现技术不同,ModelMapper是基于反射的,通过反射来查找实体对象的字段,并读取或写入值,这样的方式实现原理简单,但性能很差。与ModelMapper框架不同的是,MapStruct是基于编译阶段代码生成的,生成的转换代码在运行的时候跟一般的代码一样,没有额外的性能损失。本文重点介绍MapStruct。
原理
使用方法
1. Mapper声明
通过类似下面的代码声明一个Mapper,MapStruct会在编译时自动生成实现代码。除了基本的功能外,MapStruct提供很多高级的功能,全面支持业务中可能出现各种映射要求。示例代码如下
简要说明如下
1 - 用Mapper注解标注Mapper接口(也可以是抽象类)
2 - 可以调用其他的Mapper,来转换复杂类型的字段
3 - 可以指定一个Decorator类对Mapper实现做定制
4 - 常用的practice:声明一个静态的INSTANCE,便于调用方引用
5 - 同名的字段会自动映射,不同名的通过Mapping注解指定映射关系和映射方法
6 - 嵌套对象映射,映射到字段的成员,或成员的成员等
7 - 通过源类型和目标类型不能确定mapper的情况下,可以给mapping方法命名,在使用的时候指定特定名字的mapping方法
8 - 用constant来指定映射为一个常量值
9 - 用@MappingTarget注解指定update方法的参数中代表目标对象的参数
10 - 通过@InheritConfiguration重用映射配置,避免重复配置
上面这些特性,1,4,5,9是基本功能,使用时候一般都会用到,其他的是相对高级些的功能,可根据需要选用。MapStruct还支持列表映射,等等更多功能,不一一列举。可以参考文末的参考文档 MapStruct Reference Guide。
另外,MapStruct提供IDE插件,能够在编写映射的时候提供辅助,比如自动代码提示,重构辅助等。
2. 调用Mapper
代码如下
3. 整合进Maven
添加dependency
为Maven compile plugin设置annotation processor
4. 整合进IDE
Enable annotation processor
安装插件
使用MapStruct,有一个缺点就是,当属性改名的时候,因为在Mapper上注解中配置的名字,是在字符串里面,是不会自动同步的。但是MapStruct提供了插件来做到这一点,同时还提供代码自动提示,跳转到实现等功能。关于插件的更多信息,见 MapStruct support for IntelliJ IDEA
5. Trouble Shooting
- 找不到注释处理程序:在pom.xml中增加mapstruct-processor的依赖
- 没有找到实现类:在pom.xml中加入对mapstruct-processor的依赖
- 在IDEA里面enable Annotation Processor
- 使用Lombok的情况下,编译时报Data类的setter/getter找不到:把lombok加入到annotationProcessorPath,如下图
参考资料
MapStruct实体间转换快速入门
https://blog.csdn.net/lx_yoyo/article/details/75061614
JDK IO 2017 - Thomas Much - Easy Bean Mappings with MapStruct 1.2
https://www.youtube.com/watch?v=kKK9SczGa3I
MapStruct 1.2.0.Final Reference Guide
http://mapstruct.org/documentation/stable/reference/html
JAVA Annotation Processing技术——Lombok & MapStruct 介绍与使用
https://www.atatech.org/articles/45619
是时候去掉set/get了---浅谈data mapping技术
https://www.atatech.org/articles/45456
Lombok/Mapstruct problem: Cannot find symbol #1270
https://github.com/mapstruct/mapstruct/issues/1270