V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
alva0
V2EX  ›  Java

分享一下我的开源项目 MapStructPlus,一个更好用的 Java Bean 模型转换工具

  •  
  •   alva0 · 315 天前 · 2080 次点击
    这是一个创建于 315 天前的主题,其中的信息可能已经有所发展或是发生改变。

    MapStructPlus

    Mapstruct Plus 是 Mapstruct 的增强工具,在 Mapstruct 的基础上,实现了自动生成 Mapper 接口的功能,并强化了部分功能,使 Java 类型转换更加便捷、优雅。

    和 Mapstruct 一样,本质上都是一个基于 JSR 269 的 Java 注释处理器,因此可以由 Maven 、Gradle 、Ant 等来构建触发。

    Mapstruct Plus 内嵌 Mapstruct ,和 Mapstruct 完全兼容,如果之前已经使用 Mapstruct ,可以无缝替换依赖。


    简单示例

    假设有两个类 UserDto 和 User ,分别表示数据层对象和业务层对象:

    • UserDto
    public class UserDto {
        private String username;
        private int age;
        private boolean young;
    
        // getter 、setter 、toString 、equals 、hashCode
    }
    
    • User
    public class User {
        private String username;
        private int age;
        private boolean young;
    
        // getter 、setter 、toString 、equals 、hashCode
    }
    

    添加依赖: 引入 mapstruct-plus-spring-boot-starter 依赖:

    <properties>
        <mapstruct-plus.version>1.3.6</mapstruct-plus.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>io.github.linpeilie</groupId>
            <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
            <version>${mapstruct-plus.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <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>io.github.linpeilie</groupId>
                            <artifactId>mapstruct-plus-processor</artifactId>
                            <version>${mapstruct-plus.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
    

    指定对象映射关系

    User 或者 UserDto 上面增加注解 —— @AutoMapper,并设置 targetType 为对方类。

    例如:

    @AutoMapper(target = UserDto.class)
    public class User {
        // ...
    }
    

    测试

    @SpringBootTest
    public class QuickStartTest {
    
        @Autowired
        private Converter converter;
    
        @Test
        public void test() {
            User user = new User();
            user.setUsername("jack");
            user.setAge(23);
            user.setYoung(false);
    
            UserDto userDto = converter.convert(user, UserDto.class);
            System.out.println(userDto);    // UserDto{username='jack', age=23, young=false}
    
            assert user.getUsername().equals(userDto.getUsername());
            assert user.getAge() == userDto.getAge();
            assert user.isYoung() == userDto.isYoung();
    
            User newUser = converter.convert(userDto, User.class);
    
            System.out.println(newUser);    // User{username='jack', age=23, young=false}
    
            assert user.getUsername().equals(newUser.getUsername());
            assert user.getAge() == newUser.getAge();
            assert user.isYoung() == newUser.isYoung();
        }
    
    }
    

    小结

    引入依赖后,使用 MapStructPlus 的步骤非常简单。

    1. 给需要转换的类添加 AutoMapper 注解;
    2. 获取 Converter 实例,调用 convert 方法即可。

    该项目开发一段时间了,也逐渐趋于稳定,已在多个项目中正式应用,如果有帮助的话,求 star ~

    27 条回复    2024-01-19 13:55:23 +08:00
    zhouhu
        1
    zhouhu  
       315 天前
    其实 我感觉手写更方便,调试也简单。简单项目的话 db model 直接用
    taogen
        2
    taogen  
       315 天前   ❤️ 2
    给我的感觉:就这?

    Spring 不是有现成了方法吗。BeanUtils.copyProperties(Object source, Object target)

    至少展示一些亮点出来。
    NASK
        3
    NASK  
       315 天前
    @taogen 这个好像是 Hutool 的
    huiyadanli
        4
    huiyadanli  
       315 天前   ❤️ 3
    @taogen 两者性能不是一个级别的。这个项目是 MapStruct 的易用包装。

    而且 BeanUtils.copyProperties 甚至在有些公司已经被禁止使用了。

    建议先了解下再回复,不然一个“就这?”会让人觉的你无知又狂妄。
    taogen
        5
    taogen  
       315 天前   ❤️ 3
    @huiyadanli #4

    禁用的好像是 Apache BeanUtils
    huiyadanli
        6
    huiyadanli  
       315 天前
    @taogen #5 抱歉,忽略了 Spring 开头。不过 MapStruct 是另外一种思路,可以了解下。虽然个人更加喜欢用 idea 插件直接一把生成对象互转的方法。
    kuituosi
        7
    kuituosi  
       315 天前
    不错,已 star
    mmdsun
        8
    mmdsun  
       315 天前
    借楼 想问问,MapStruct 支持深拷贝吗?嵌套大对象的性能怎么样?
    很多框架,对象里面嵌套的对象拷贝只支持引用,一修改就都修改了。
    layxy
        9
    layxy  
       314 天前
    @taogen spring 的性能不太好,MapStruct 会生成代码,性能和 getset 差不多
    RedBeanIce
        10
    RedBeanIce  
       314 天前
    楼主加油,冲啊!

    上面的部分人估计没写过复杂项目。
    eleganceoo
        11
    eleganceoo  
       314 天前
    楼主加油,很多 bean 八九十个字段,的确需要这样的方法,目前使用 hutool BeanUtil
    chuck1in
        12
    chuck1in  
       314 天前
    @huiyadanli 国内的技术人员里面很多这种喜欢莫名其妙贬低别人的人。不知道为啥内心这么阴暗。

    另外想已经 star op 的仓库了,求互相 star 。

    https://github.com/ccmjga/mjga-scaffold
    https://www.mjga.cc
    litchinn
        13
    litchinn  
       314 天前   ❤️ 2
    本来是推自己的 mapstructplus 的,变成讨论 mapstruct 的了,哈哈
    mapstruct 本身是通过编译期生成 getset 方法来实现转换的,就和 lombok 生成 getset 方法一样,因此这两者同时使用还需要额外配置
    因为是 getset ,所以 mapstruct 的性能要优于 BeanUtils.copyProperties ,通常认为偶尔使用且数据量小的情况可以直接使用 BeanUtils.copyProperties ,否则使用 mapstruct 或者自己写 getset 比较好
    关于深度拷贝,mapstruct 是支持的,也是需要额外的配置,不复杂
    mapstruct 还提供 SPI

    回到楼主这,楼主说 plus 对 mapstruct 做了增强,也就是连本来需要自己写的 Mapper 也通过 mapstruct-plus-processor 生成了。感觉楼主介绍的时候得强调下你做了哪些增强,本来是啥样,之后是啥样,例如楼上问到的深拷贝等,在你这里应该如何使用。

    最后想问下,这个 @AutoMapper 支持多个 target 吗,如果我 User 想转成多种 UserVO 要怎么使用呢?
    alva0
        14
    alva0  
    OP
       314 天前
    @kuituosi 感谢支持
    alva0
        15
    alva0  
    OP
       314 天前   ❤️ 1
    @mmdsun 如果两个对象的同名属性都是同一个自定义类,是引用传递的。

    嵌套大对象没啥问题,都是调用 getter/setter 方法来拷贝类的
    alva0
        16
    alva0  
    OP
       314 天前
    @chuck1in 已 star
    alva0
        17
    alva0  
    OP
       314 天前
    @taogen #2 我写的示例比较简单,可以看一下文档,测试下实际的运行效果
    alva0
        18
    alva0  
    OP
       314 天前
    @RedBeanIce 🤣感谢支持
    alva0
        19
    alva0  
    OP
       314 天前
    @eleganceoo 可以体验下
    alva0
        20
    alva0  
    OP
       314 天前
    @litchinn 本来也是基于 mapstruct 实现的。

    主要是省略手写 Mapper 的过程,通过在类上面增加注解的方式,来生成转换接口,这是最主要的增强。同时还有一些别的,可以看下文档。

    支持多个,可以通过注解 @AutoMappers 来配置多个类
    BQsummer
        21
    BQsummer  
       314 天前
    @taogen copyProperties 是运行时反射, MapStruct 是编译时, 性能差距很大
    rockyastor
        22
    rockyastor  
       314 天前
    公司内是大量但不深度使用 mapstruct 的,这样一个 plus 库很实用,已 star !
    alva0
        23
    alva0  
    OP
       314 天前
    @rockyastor 也是为了解决自己的痛点,开源出来的,感觉支持😁
    zhazi
        24
    zhazi  
       314 天前   ❤️ 2
    这个么一个小 kit 和整个 spring 生态做耦合,里面还塞了一个 hutool 的大杂烩,也没有测试
    alva0
        25
    alva0  
    OP
       314 天前
    @zhazi 后面会考虑拆出来的
    Aresxue
        26
    Aresxue  
       314 天前
    有对应的 idea 插件吗,当字段类型不一致时做提示(可配置为严格模式,严格模式直接报编译错误),还有两个实体的字段差异最好也能在悬浮窗上展现出来,感觉现有的 bean copy 在这方面都不咋的。
    alva0
        27
    alva0  
    OP
       314 天前
    @Aresxue MapStruct 倒是有这个插件,我后面考虑开发一个
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1379 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:37 · PVG 01:37 · LAX 09:37 · JFK 12:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.