为了解决 Java 对象转换的痛点,我开发了一款 IDEA 插件

2022-07-04 13:28:48 +08:00
 RookieRicardo

背景

一切还要从我的上一家公司讲起,我的上一家公司是一家独角兽企业,说大不大说小不小的那种,公司氛围也是比较注重技术,我当时入职之后的第一课就是阅读我们 CTO 写的开发规范,其中他把 Java 项目的目录结构划分的非常清楚,大概是下面这个样子的:

我当时觉得这种分层结构划分的非常优雅与合理,当然以上只是一个大概,更细节的分层我没有表露,但是随之而来在实际中使用的过程中,这样一个三层结构也带来了一个问题,那就是对象传输非常麻烦,因为每层都会有一个特有的对象。

下面我举一个例子,假如我们要插入一个 User 对象,那么它可能要经过以下二次对象转换:

以上只是一个比较简单的例子,相信大家已经可以从中看出开发者们需要写一些很繁琐但是很没意思的代码(手动 get/set),比如上图中的三个对象可能字段都是一模一样的,但却需要重复写两次 Convert 去进行对象的转换。

当然这样设计当然也有好处,那就是解耦,比如我们现在用的数据库是 Mysql,如果要换成 Mongo 只需要把第二次对象转换的代码稍微修改一下即可,这也是这样设计的初衷。

常见方案

这么一个繁琐的事难道就没有一些方案进行解决吗?当然有,一般来说有两种方式:

  1. BeanUtil / JSONObject
  2. MapStruct

先来说第一种方式吧,无论 BeanUtil 是深拷贝还是浅拷贝,它对我们开发者来说细节都是不可见的,一旦某个字段赋值出现了问题,我们并没有办法去进行代码的排查,因为我们没办法查看对象转换的细节,JSONObject 也有相同的问题。

然后就是第二种方式,MapStruct 在前段时间是一个非常火的方案,它和 Lombok 非常类似,在代码编译期帮助我们去生成对象之间的转换代码,我们也可以通过 IDEA 的提示去查看编译后的代码,我司除了手动 get/set 代码,最多的就是使用 MapStruct 进行处理。

但是对我而言,MapStruct 还是有一些缺点,首先我的 IDEA 经常没有查看编译后代码的提示,其次就是如果转换对象的某个字段不一样的时候,需要学习 MapStruct 的一些用法进行处理,有一定的学习负担,反正我到现在都没学会😂。

我的方案

最终我为了方便,决定自己开发一个 IDEA 插件并起名为 BeanMappingKey,目前已经迭代到 1.X 版本,主要思想是通过插件的方式为我们需要转换的对象自动生成转换代码。

目前暂时有三种用法:

  1. 根据对象生成对应的 get/set 方法,支持建造者模式。
  2. 根据 Class 生成对应的 get/set 方法,支持建造者模式。
  3. 根据一个方法的入参和返回值,进行对象的转换代码生成,支持建造者模式。

其中,第一种和第二种生成起来是差不多的,具体可见以下例子:


上图的示例,是我们选中一个 Class 类进行代码的生成,根据这个类是否是建造者模式,来生成对应风格的代码,生成之后的代码被拷贝到剪贴板上,可以自由粘贴。

第二种方式,对于我来说是更加常用的,因为转换代码往往是写在一个方法里面的,通过选中方法名匹配入参和返回值进行代码生成,类似下面的例子:

匹配的逻辑就是根据字段名进行匹配,匹配失败的话则会留空,同时不只支持一个入参,可以对多个入参进行匹配,就像下面这样:


以上就是我对这个插件的介绍了,各位读者如果有兴趣的话可以在 IDEA 上面下载上试试:

注:暂且只支持 2020 以上版本的 IDEA ,安装之后无需重启。

目前我的这个插件依然还在完善中,对于复杂类型支持的还不够完善,比如对象里面嵌套对象的情况,我打算下一阶段继续对这块痛点进行升级完善,下面是此插件的地址:


2022-06-06 更新:插件更新 2.0 版本,已经支持对象嵌套的生成,欢迎大家在 IDEA 中下载使用。

5420 次点击
所在节点    分享创造
53 条回复
A555
2022-07-04 15:53:07 +08:00
差不多,之前是写了个泛型的方法,处理一些结构一模一样的 bean 类转换
Leviathann
2022-07-04 16:23:05 +08:00
@RookieRicardo 现在 web 框架应该都有把 querystring 自动转成复合对象的功能
pengtdyd
2022-07-04 19:06:32 +08:00
《比如我们现在用的数据库是 Mysql ,如果要换成 Mongo 》在实际的项目开发中,99.99%不会涉及需要换数据库的情况。过度的设计是软件开发中的大忌,软件产品的生命周期只有 18 个月,如此冗余的设计会让开发者不堪重负!
RookieRicardo
2022-07-04 19:18:25 +08:00
@ql562482472 这个并不支持方法自动匹配生成,所以我才自己写了。
RookieRicardo
2022-07-04 19:19:20 +08:00
@Leviathann 请求参数转对象都是可以的,这个主要是内部的 DTO 转换。
RookieRicardo
2022-07-04 19:21:05 +08:00
@pengtdyd 那我换个例子吧,其实我觉得我们没必要争论这个,这里可以不是数据库而是远程接口,之前我们都是在这一层接远程接口用的,远程接口的参数变化是常见的。
RookieRicardo
2022-07-04 19:21:43 +08:00
@zamaojava 这个并不支持方法匹配入参和出参生成,所以我才自己写了。
zamaojava
2022-07-04 19:47:21 +08:00
@RookieRicardo 可以啊,只是文档没写,而且技巧很隐蔽
RookieRicardo
2022-07-04 21:22:27 +08:00
@zamaojava 哈哈 文章里面有说 不过是在中间说的 看来我应该加粗一下
SimpleSS
2022-07-04 22:45:16 +08:00
好用,赞一个,干了我一直想干的一件事,虽然我们是 netty 的项目,也经常要写一堆 model ,这样生产不容易漏字段
Jooooooooo
2022-07-04 22:52:28 +08:00
正好需要这个, 我来试试看.
cubecube
2022-07-04 23:06:45 +08:00
@zamaojava 我记得生成一个对象,需要手动改下命名吧
russ44
2022-07-05 11:17:35 +08:00
试用一下
justin2018
2022-07-06 07:47:55 +08:00
好东西 安装了 😁
Asimov01
2022-07-06 11:01:56 +08:00
很棒,感谢贡献 🎉
RookieRicardo
2022-07-06 11:45:15 +08:00
@SimpleSS 好用的话可以向同事推荐一下
RookieRicardo
2022-07-06 11:46:37 +08:00
@Asimov01 能帮到大家就好
yveJohn
2022-07-06 18:00:09 +08:00
个人认为如果可以加上集合对象的转换就更加完美了,例如 List<PO> -> List<DTO>
siweipancc
2022-07-07 09:08:49 +08:00
idea 新版本的 JPA 插件已经默认集成了这个功能了 b
ychost
2022-07-07 09:24:52 +08:00
我还是喜欢 BeanUtils 一把梭,深拷贝就用 JSON 序列化,一般深拷贝用的比较少,除非领域模型真的非常重,嵌套非常多

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

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

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

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

© 2021 V2EX