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

111 天前
 alva0

MapStructPlus

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

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

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


简单示例

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

public class UserDto {
    private String username;
    private int age;
    private boolean young;

    // getter 、setter 、toString 、equals 、hashCode
}
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 ~

1696 次点击
所在节点    Java
27 条回复
zhouhu
111 天前
其实 我感觉手写更方便,调试也简单。简单项目的话 db model 直接用
taogen
111 天前
给我的感觉:就这?

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

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

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

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

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

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

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

https://github.com/ccmjga/mjga-scaffold
https://www.mjga.cc
litchinn
110 天前
本来是推自己的 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
110 天前
@kuituosi 感谢支持
alva0
110 天前
@mmdsun 如果两个对象的同名属性都是同一个自定义类,是引用传递的。

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

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

支持多个,可以通过注解 @AutoMappers 来配置多个类

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1009758

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX