Mapstruct中类型的映射规则(二)_mapstruct 父类属性-程序员宅基地

技术标签: mapstruct  

        上一篇文章主要讲解了Mapstruct的介绍、Mapstruct的优缺点、MapStruct简单的映射示例以及和常见的映射工具做了性能上的对比。

        这篇文章主要讲解Mapstruct的属性之间的映射规则,只有了解了这些规则之后,你才能更好地理解mapstruct如何做映射,才能按照你的想法进行对象属性之间的映射。

在属性映射方面,mapstruct相比于其他映射工具有:

  • 可以进行不同属性名之间的映射,使用@Mapping注解的source和target
  • 可以使用表达式进行设置,使用@Mapping注解中的expression
  • 可以设置默认值,使用@Mapping注解中的constant,
  • 可以进行不同类型之间的映射,并且更加安全
  • 可以进行自定义映射方法

01

mapstruct的映射文档


1.可以参考mapstruct的doc的第五章了解完整的映射规则:这里

02

mapstruct的映射控制说明


2.1 映射控制的作用:

        在源对象目标对象之间进行映射时,哪种映射方法将被考虑。即:只有在有这个控制条件下,才会执行对应的映射方法。

        所有属性之间的复制或者拷贝都将是依据以下映射控制来完成的。只有更好地理解这四种映射控制,才能按照我们的想法进行对象之间的拷贝。

2.2 映射控制的种类:

mapstruct一共有四种映射控制

  • MappingControl.Use.DIRECT

        直接映射:直接将源属性赋值到目标属性上,如果是对象的话,就是指针复制,也就是浅拷贝。这种方法有一个前提:目标属性是源属性的父类或者相同类型

  • MappingControl.Use.BUILT_IN_CONVERSION

        内置映射:将使用mapstruct内置的映射方法。有哪些内置映射方法:具体可参考文档第五章中第一节中。例如:日期和字符串、原生类型和对应的包装对象、字符串和枚举类型等等。

  • MappingControl.Use.MAPPING_METHOD

        映射方法:包含两类:可以是自定义的映射方法,也可以是系统自动生成的映射方法。注意:自定义映射方法比系统自动生成的映射方法的优先级更高。例如:深度拷贝就是使用这个映射控制。系统自动生成的映射方法:一般都是对象之间的映射。

  • MappingControl.Use.COMPLEX_MAPPING

        复合映射:是一种结合BUILT_IN_CONVERSIONMAPPING_METHOD的映射控制来完成对象属性之间的拷贝。当进行COMPLEX_MAPPING时:一共有三种形态:

                a) target = method1( method2( source ) )

                b) target = method( conversion( source ) )

                c) target = conversion( method( source ) )

        其中method开头表示:自定义映射方法,conversion开头的表示:内置映射方法

        注意:复合映射中只能进行两次转化,不能多于两次,也不能少于两次。这三种形态不含两个内置映射方法来完成属性之间的拷贝。即:至少有一个自定义的映射方法的存在。

        注意:在没有某一中映射控制时,就不会采用这种方式完成属性映射,例如:没有MAPPING_METHOD就会不采用自定义的映射方法完成属性映射。

2.3 映射控组组合

        四种映射控制可以组合使用,即同时使用两个及以上的映射控制,从而在这些映射控制中选择一种方式使用。那这就涉及到映射控制之间优先级

2.4 mapstruct内置的映射控制组合

        在mapstruct中一共有三种内置的映射控制组合,以及自定义的映射组合。

  • @MappingControl注解类

            该注解使用了全部的映射控制:DIRECT、MAPPING_METHOD、 BUILT_IN_CONVERSION、COMPLEX_MAPPING。这也这是:默认使用映射控制。
  • @DeepClone注解类

           该注解只使用了:MAPPING_METHOD映射,当我们使用这个注解时,将不会采用其他的三种方式来完成属性之间的拷贝。
  • @NoComplexMapping注解类

           改注解使用了三种:DIRECT、MAPPING_METHOD、 BUILT_IN_CONVERSION,即将不会使用复合映射方法完成属性之间的拷贝
  • 自定义的映射组合

                我们可以声明一个注解类,自定义只是用哪些映射控制,例如:只使用内置的映射方法

package com.moxiao.mapstruct.annotation;

import org.mapstruct.control.MappingControl;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * @author moxiao
 */
@Retention(value = RetentionPolicy.CLASS)
@MappingControl( MappingControl.Use.BUILT_IN_CONVERSION )
public @interface BuildInConversionControl {
}

2.5 映射控制的使用

        mapstruct默认使用的是:@MappingControl注解类,即四种映射控制

        我们可以在@Mapper注解中的mappingControl属性中设置,他的属性值是一个注解类。在@Mapper注解中设置这个属性:将会应用到这个类中的所有方法的属性之间的拷贝

        我们也可以在@Mapping注解中的mappingControl属性中设置。在@Mapping注解中设置这个属性:将只会应用到指定属性上。

        @Mapping的优先级比@Mapper的高,即优先采用@Mapping,如果没有才会使用@Mapper进行属性之间的映射。

03

mapstruct的映射控制优先级


        在有多个映射控制使用时,例如在使用:@MappingControl注解,mapstruct将会如何进行属性之间的映射。这里就涉及到四种映射控制之间的优先级。

3.1 四种映射控制的优先级,从高到低

  1. 在有MAPPING_METHOD控制下,并且包含有一个自定义的映射方法。这个自定义方法必须满足:输入参数源属性父级或者相同类型,这个映射方法的返回值目标属性的子类或相同类型。必须都满足这两个条件:这样在进行属性拷贝时,才会使用自定义的映射方法。不然则跳过。
  2. 在有DIRECT控制下,并且目标属性必须是源属性的父类或者相同类型。功能:直接将源属性的指针拷贝到目标属性下。必须满足这两个条件,才会使用指针拷贝,不然则跳过。
  3. 如果有BUILT_IN_CONVERSION的控制下,在源属性和目标属性之间拷贝时,mapstruct就会根据源属性类型和目标属性类型找到对应的内置映射方法使用,没有找到,就跳过。
  4. 如果有COMPLEX_MAPPING控制下,它又划分成三种类型:

                 如果存在两个自定义的方法,可以将源属性转化为目标属性,即: target = method1( method2( source ) ),优先使用。

                如果有一个自定义方法,一个内置映射方法,可以将源属性转化为目标属性,就会使用其中一个target = method( conversion( source ) )或者target = conversion( method( source ) )。

     5. 如果有MAPPING_METHOD控制下,将自动生成一个映射方法,完成属性之间的映射。必须对象,属性不能是:8中基本类型和对应的包装类以及String

3.2 注意事项:

        如果源属性是8种基本类型或者包装体,而目标属性是对应的类型(不能是不对应的),则会直接拷贝。就算有就不会走上面的优先级。例如:源属性为long,目标属性为Long,不管配置的什么,都会直接赋值。

04

mapstruct的映射控制的示例


1.源对象

public class MappingOrder {

    private String name;

    private Integer age;

    private LocalDateTime birthTime;

    private MapperOrderChild mapperOrderChild;

    private MappingOrderChildChild mapperOrderChild2;
    //省略其set/get方法
 }

2.目标对象

public class MappingOrderVO {

    private String name;

    private Number age;

    private String birthString;

    private MapperOrderChild mapperOrderChild;

    private MapperOrderChild2 mapperOrderChild2;
 }

3.映射类(必须自己单独定义一个,mapstruct必须提供一个mapper接口或者抽象类)

package com.moxiao.mapstruct.mapper;

import com.moxiao.mapstruct.entity.MappingOrder;
import com.moxiao.mapstruct.entity.MappingOrderVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.control.DeepClone;

/**
 * @author moxiao
 */
@Mapper
public interface MapperOrderMapper {

    @Mapping(source = "birthTime", target = "birthString", dateFormat = "yyyy-MM-dd HH:mm:ss")
    //这一行进行深度拷贝,注意最后一个参数很重要:mappingControl = DeepClone.class
    @Mapping(source = "mapperOrderChild2", target = "mapperOrderChild2", mappingControl = DeepClone.class)
    MappingOrderVO entityToVo(MappingOrder mappingOrder);
    
}

4.mapstruct自动生成的文件

public class MapperOrderMapperImpl implements MapperOrderMapper {

    @Override
    public MappingOrderVO entityToVo(MappingOrder mappingOrder) {
        if ( mappingOrder == null ) {
            return null;
        }

        MappingOrderVO mappingOrderVO = new MappingOrderVO();
        
        //第一个属性,因为没有自定义方法从LocalDateTime转化为String,将跳过,
        //不能直接映射,优先级第二条
        //mapstruct有一个从LocalDateTime转化为String的内置方法,从而满足第三条映射
        if ( mappingOrder.getBirthTime() != null ) {
            mappingOrderVO.setBirthString( DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss" ).format( mappingOrder.getBirthTime() ) );
        }
        
        //我们在方法中使用DEEPCLONE,即MAPPING_METHOD控制
        //所以只有第一条优先级和第五条优先级,满足。因为没有自定义映射方法,从而跳过
        //所以Mapstruct使用第五条,自动生成一个映射方法
        mappingOrderVO.setMapperOrderChild2( mappingOrderChildChildToMapperOrderChild2( mappingOrder.getMapperOrderChild2() ) );
        //DIRECT优先级获胜
        mappingOrderVO.setName( mappingOrder.getName() );
        //DIRECT优先级获胜
        mappingOrderVO.setAge( mappingOrder.getAge() );
        //DIRECT优先级获胜
        mappingOrderVO.setMapperOrderChild( mappingOrder.getMapperOrderChild() );
        return mappingOrderVO;
    }

    protected MapperOrderChild2 mappingOrderChildChildToMapperOrderChild2(MappingOrderChildChild mappingOrderChildChild) {
        if ( mappingOrderChildChild == null ) {
            return null;
        }
        MapperOrderChild2 mapperOrderChild2 = new MapperOrderChild2();

        mapperOrderChild2.setFirstName( mappingOrderChildChild.getFirstName() );
        mapperOrderChild2.setSecondName( mappingOrderChildChild.getSecondName() );

        return mapperOrderChild2;
    }
}

结论:最终生成的Java映射代码,会根据01章节中第5条的映射优先级,进行属性之间的映射。

更多精彩内容:请关注公众号:


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cw_hello1/article/details/120193123

智能推荐

leetcode 172. 阶乘后的零-程序员宅基地

文章浏览阅读63次。题目给定一个整数 n,返回 n! 结果尾数中零的数量。解题思路每个0都是由2 * 5得来的,相当于要求n!分解成质因子后2 * 5的数目,由于n中2的数目肯定是要大于5的数目,所以我们只需要求出n!中5的数目。C++代码class Solution {public: int trailingZeroes(int n) { ...

Day15-【Java SE进阶】IO流(一):File、IO流概述、File文件对象的创建、字节输入输出流FileInputStream FileoutputStream、释放资源。_outputstream释放-程序员宅基地

文章浏览阅读992次,点赞27次,收藏15次。UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节。文件字节输入流:每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1。注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。UTF-8字符集:汉字占3个字节,英文、数字占1个字节。GBK字符集:汉字占2个字节,英文、数字占1个字节。GBK规定:汉字的第一个字节的第一位必须是1。_outputstream释放

jeecgboot重新登录_jeecg 登录自动退出-程序员宅基地

文章浏览阅读1.8k次,点赞3次,收藏3次。解决jeecgboot每次登录进去都会弹出请重新登录问题,在utils文件下找到request.js文件注释这段代码即可_jeecg 登录自动退出

数据中心供配电系统负荷计算实例分析-程序员宅基地

文章浏览阅读3.4k次。我国目前普遍采用需要系数法和二项式系数法确定用电设备的负荷,其中需要系数法是国际上普遍采用的确定计算负荷的方法,最为简便;而二项式系数法在确定设备台数较少且各台设备容量差..._数据中心用电负荷统计变压器

HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板_网页设计成品百度网盘-程序员宅基地

文章浏览阅读7k次,点赞4次,收藏46次。HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 等网页设计题目, A+水平作业_网页设计成品百度网盘

【Jailhouse 文章】Look Mum, no VM Exits_jailhouse sr-iov-程序员宅基地

文章浏览阅读392次。jailhouse 文章翻译,Look Mum, no VM Exits!_jailhouse sr-iov

随便推点

chatgpt赋能python:Python怎么删除文件中的某一行_python 删除文件特定几行-程序员宅基地

文章浏览阅读751次。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。AI职场汇报智能办公文案写作效率提升教程 专注于AI+职场+办公方向。下图是课程的整体大纲下图是AI职场汇报智能办公文案写作效率提升教程中用到的ai工具。_python 删除文件特定几行

Java过滤特殊字符的正则表达式_java正则表达式过滤特殊字符-程序员宅基地

文章浏览阅读2.1k次。【代码】Java过滤特殊字符的正则表达式。_java正则表达式过滤特殊字符

CSS中设置背景的7个属性及简写background注意点_background设置背景图片-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏17次。css中背景的设置至关重要,也是一个难点,因为属性众多,对应的属性值也比较多,这里详细的列举了背景相关的7个属性及对应的属性值,并附上演示代码,后期要用的话,可以随时查看,那我们坐稳开车了······1: background-color 设置背景颜色2:background-image来设置背景图片- 语法:background-image:url(相对路径);-可以同时为一个元素指定背景颜色和背景图片,这样背景颜色将会作为背景图片的底色,一般情况下设置背景..._background设置背景图片

Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程-程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏8次。Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程

PyCharm2021安装教程-程序员宅基地

文章浏览阅读10w+次,点赞653次,收藏3k次。Windows安装pycharm教程新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入下载安装PyCharm1、进入官网PyCharm的下载地址:http://www.jetbrains.com/pycharm/downl_pycharm2021

《跨境电商——速卖通搜索排名规则解析与SEO技术》一一1.1 初识速卖通的搜索引擎...-程序员宅基地

文章浏览阅读835次。本节书摘来自异步社区出版社《跨境电商——速卖通搜索排名规则解析与SEO技术》一书中的第1章,第1.1节,作者: 冯晓宁,更多章节内容可以访问云栖社区“异步社区”公众号查看。1.1 初识速卖通的搜索引擎1.1.1 初识速卖通搜索作为速卖通卖家都应该知道,速卖通经常被视为“国际版的淘宝”。那么请想一下,普通消费者在淘宝网上购买商品的时候,他的行为应该..._跨境电商 速卖通搜索排名规则解析与seo技术 pdf

推荐文章

热门文章

相关标签