方便高效的JAVA对象转换工具
1. 简介
lamia
是一个高性能的Java 实体映射工具, 使用简单的注解就能帮助你在编译期
生成对应的转换代码
项目地址:
- github
- gitee
1.1 优势
- 方便灵活的
编译期
快速生成转换代码 - 支持和
lombok
等AnnotationProcessor
框架同时使用 - 支持Map/List 等集合类型之间的转换
- 不依赖
idea插件
- 支持
idea
的增量编译
1.1 和 MapStruct的区别
本框架和MapStruct
类似,都是在编译期
生成对应的转换代码,那么作者为什么要去重复造这个轮子?
作者本身也是MapStruct
的使用者,但是对于MapStruct
有以下几个问题
- 转换方法是以
接口
的方式去定义的,需要手动调用Mappers.getMapper(转换接口.class)
,来获取正真的
转换实现类,对代码有一定的耦合
- 对于很复杂的对象转换,需要在
注解
中定义对应的表达式, 其实很多时候,这个表达式写完我自己手写set
转换也写完了
,对于我这样的码农来说,没有任何提示的情况下写表达式很不舒服
基于以上几点,作者我写了Lamia
, 在快速生成转换代码的同时,提供了更高的灵活性
2. 快速使用
支持环境
JDK8
及以上版本
1.引入maven坐标
<dependency><groupId>io.github.cao2068959</groupId><artifactId>lamia</artifactId><version>1.2.4</version>
</dependency>
如果需要手动编译请先clone下本仓库, 然后执行maven命令
mvn clean install
注意: 编译环境只能使用JDK8
, JDK9
以上的版本把sun.tools.jar
的包给模块化了,可能会导致编译失败
但是用JDK8
编译出来的版本可以兼容JDK9
及以上版本
2.写一个转换方法
并标注上注解@Mapping
3.在转换方法
里面调用生成赋值语句的静态方法
MyType varName = (强转成你要返回的类型)Lamia.convert(转换的参数);
对应的最简demo
如下所示
public class Test {public static void main(String[] args) {User user = User.builder().address("dewdewd").name("name").old(312).chy("ffw").build();Test main = new Test();System.out.println(main.toVO(user));}@MappingUserVO toVO(User user) {return (UserVO) Lamia.convert(user);}
}@Data
@Builder
public class User {String name;Integer old;String address;
}@Data
public class UserVO {String name;Integer old;String address;
}
对应编译之后的代码如下:
这里需要注意的是:
- 生成的实体必须要有对应的
构造方法
/setter方法
, 如果某个字段在构造方法
/setter方法
里都不存在,那么这个字段将不会被设置进去- 如果有多个
构造方法
,那么将会选择和被转换对象
中最匹配的
- 如果有多个
被转换对象
中需要有对应的getter
方法
3. 进阶教程
3.1 @Mapping
对于标注了注解@Mapping
的方法, 那么在编译期
中将会去扫描这个方法中的每一行代码, 直到扫描到语句
Lamia.convert
, 然后根据Lamia.convert
中配置的参数来生成对应的转换代码, 然后使用生成的代码替换掉语句
Lamia.convert
注意: 这里生成对应的转换代码后,不是整个方法去替换的,而是仅仅只是替换Lamia.convert
语句
如下代码所示, 在调用Lamia.convert
之前还有,对应的打印代码
@Mappingvoid printlnUserVO(User user) {System.out.println("代码转换前--------------------->");UserVO userVO = (UserVO) Lamia.convert(user);System.out.println("代码转后<---------------------");System.out.println(userVO);}
对应生成的代码如下所示:
注意: 一个方法里面可以同时存在多个 Lamia.convert
语句
如下面代码所示,在一个标注了 @Mapping
的方法中有多个转换语句
@Mappingvoid printlnUserVO(User user) {//转换成mapMap<String, Object> map = (HashMap<String, Object>) Lamia.convert(user);System.out.println(map);//转换成userVOUserVO userVO = (UserVO) Lamia.convert(user);System.out.println(userVO);}
生成的代码如下所示
3.2 Lamia.convert 语句
在本框架的类Lamia
中提供了一个 静态方法 convert(Object... param)
, 对于应用程序来说
该方法没有任何的意义, 因为这个方法没有干任何的事情, 但是在编译期间对于本框架来说确是至关重要的
本框架的核心引擎将会把这个方法替换成真正的转换代码, 这里需要配合@Mapping
注解使用
在调用Lamia.convert
方法的时候,需要注意的是, 调用该方法的时候必须设置 转换入参
,强转类型
, 接收属性
三个部分
3.2.1 强转类型
这里强转类型
代表的是真正生成的实例类型, 而接收参数可以是对应的父类
, 如下所示
Map<String, Object> map = (HashMap<String, Object>) Lamia.convert(user);
这里把user
对象转成Map
类型, 强转类型中使用的HashMap
, 那么生成的真正实例就是HashMap
- QA:
- 问: 这里为什么要使用强转,而不是直接把要转成的类型放入方法的第一个参数如: 定义成
public static T convert(Class<T> tClass, Object... param)
的形式 - 答: 因为如果把要转换的类型放入第一参数,那么就将会丢失泛型, 如下面使用是不合法的
- 问: 这里为什么要使用强转,而不是直接把要转成的类型放入方法的第一个参数如: 定义成
3.2.2 转换入参
可以注意到,该静态方法使用的是可变参数, 所以你可以将无限多的参数给放入进去, 从而转换出一个聚合的对象.
如下所示:
@MappingUserVO toVO(User user) {String name = "myName";//这里需要注意的是,UserVO对象中有一个叫做 name并且类型也是String的字段,而且有对应的setter或者构造方法return (UserVO) Lamia.convert(user, name);}
生成的代码如下所示:
对于入参是有对应的优先级的, 默认情况下: 单独字段 > 对象中包含的字段
, 所以这里 name > user.name
注意: 优先级是可以修改的,具体可以看 3.3 @MapMember
的使用
3.3 @MapMember
当调用Lamia.convert(Object... param)
方法的时候可以向方法的参数中传入需要参加转换的原数据,
Lamia
是通过传入参数的字段名称
来映射对应生成对象的字段的, 那么如果我传入的字段
名称和需要映射的字段名称不同
那么可以在对应的传入字段
上打上@MapMember
注解, 如下所示
@MappingUserVO toVO(User user) {@MapMember("name") String what = "what";return (UserVO) Lamia.convert(user, what);}
生成的代码如下所示:
3.3.1 入参优先级
Lamia.convert(Object... param)
如果有多个入参,那么是可以设置入参的优先级的, 在不去手动设置优先级的情况下,遵循两个原则
单独字段 > 对象中包含的字段
, 这个上面演示过,就不过多说明了- 如果2个字段都是
单独字段
或者都是对象中包含的字段
的情况下, 在方法Lamia.convert(Object... param)
入参中越靠前的优先级越高
具体式例如下:
@MappingUserVO toVO(User user) {@MapMember("name") String what = "what";@MapMember("name") String why = "why";return (UserVO) Lamia.convert(user, what, why);}
如上面也可以看出, 同样优先级的2个入参, 放前面的那个生效, 所以上述代码最后设置进去的是 what
如果把默认
优先级用一个数字标识出来,那么就是
单独字段
: 10对象中包含的字段
: 5
数字越大优先级越高
当然, 优先级也是可以手动去控制的, 在注解@MapMember
中有一个方法priority()
就是用来设置优先级的如下所示
@MappingUserVO priorityTest(User user) {@MapMember(value = "name", priority = 4) String what = "what";return (UserVO) Lamia.convert(user, what);}
user
是用的对象里面的字段, 所以默认的优先级是5
, 而我手动设置了name
变量优先级是4
(默认是10
) , 所以编译后的代码如下所示
同时, priority()
也能作用于对象上面,让所有映射的字段都具有优先级, 如下所示:
@MappingUserVO priorityTest(User user) {@MapMember(spread = true, priority = 2) DetailedUser detailedUser = DetailedUser.builder().address("DetailedUser_address").name("DetailedUser_name").email("704188931@qq.com").old(1).build();return (UserVO) Lamia.convert(detailedUser, user);}@Data@Builderpublic class User {String name;Integer old;String address;}@Data@Builderpublic class DetailedUser {String name;Integer old;String address;String email;}@Datapublic class UserVO {String name;Integer old;String address;String email;}
这里 仅仅是 DetailedUser
对象多了一个 email
字段,其他字段完全一样, 那么我想name
/old
/address
三个共有字段使用User
对立面的, 而email
字段使用DetailedUser
里面的, 那么仅仅只需让 DetailedUser
的优先级高于User
即可
所以编译后的代码如下所示:
3.3.2 spread
当向Lamia.convert(Object... param)
方法中传入了一个对象, 那么到底是把这个对象中的所有字段都映射到结果对象的字段中,
还是把这个对象当做一个字段放入结果对象中?
因为这个分歧, 所以有了 spread
, 这里spread
的意思是 展开,扩散 的意思,这里 扩散 的是对象中的字段
在@MapMember
注解中有一个 spread()
方法用来标识这个对象
到底需不需要 spread
, 当然在不去写@Mapping
注解的时候也是有spread
默认值的
- 当对象来自
方法入参
的时候:spread=true
- 当对象来自
方法内部定义变量
的时候:spread=false
如下所示:
@MappingUserVO spreadTest(User childUser) {return (UserVO) Lamia.convert(childUser);}
因为childUser
参数来自于 方法入参
, 所以默认 spread=true
, 那么将会映射childUser
中所有属性到UserVO
中
编译结果如下:
如果使用方法内部参数
@MappingUserVO spreadTest() {User childUser = User.builder().address("dewdewd").name("name").old(312).build();return (UserVO) Lamia.convert(childUser);}
那么就将会把方法变量childUser
当做一个字段给设置进入UserVO.childUser
编译结果如下:
当然这里可以使用@MapMember
注解去更改spread
的值, 如下所示
@MappingUserVO spreadTest(@MapMember(value = "childUser", spread = false) User user) {@MapMember(spread = true) User childUser = User.builder().address("dewdewd").name("name").old(312).build();return (UserVO) Lamia.convert(childUser, user);}
编译结果如下所示
4. 常用数据结构的转换
Lamia
也支持一些常用数据结构的转换
4.1 Map
支持对象和map
之间的相互转换, 这里泛型将会被擦除
, 生成的Map
类型为HashMap<String,Object>
, 请确保类型的统一
@MappingMap<String, Object> toMap(User user) {return (HashMap) Lamia.convert(user);}@MappingUserVO mapToUser(Map<String, Object> map) {return (UserVO) Lamia.convert(map);}
编译后的代码分别为:
4.2 List之间的转换
同时也支持2个集合对象之间的转换 如: List<User> --> List<UserVO>
的转换
@Mappingvoid listTest(List<User> users) {List<UserVO> result = (List<UserVO>) Lamia.convert(users);//转换后的结果中再添加一个自定义对象result.add(new UserVO());}
同时在两个集合相互转换的时候, 可以去覆盖某个字段的值如下:
@Mappingvoid listTest(List<User> users) {@MapMember(value = "name", priority = 10) String test = "listTest";List<UserVO> result = (List<UserVO>) Lamia.convert(users, test);//转换后的结果中再添加一个自定义对象result.add(new UserVO());}
4.3 Optional的支持
当映射的字段 名称能够对应上, 仅仅只是类型不同的情况下, 如果发现是Optional
的包装类型, 那么将会自动拆/装包
,
Optional<String> name
和String name
之间是可以想换转换的
定义一个实体,里面的字段都是Optional
的如下:
@Data
public class Anonymous {Optional<String> name;Optional<Integer> old;Optional<Integer> address;
}
然后和正常的User
对象进行转换
@MappingAnonymous toAnonymous(User user) {return (Anonymous) Lamia.convert(user);}@MappingUserVO toUser(Anonymous anonymous) {return (UserVO) Lamia.convert(anonymous);}
编译后的代码如下所示
方便高效的JAVA对象转换工具相关推荐
- 自定义java对象转换工具类
背景 项目中经常有VO.PO.DTO等之间转换,由于apache工具类中BeanUtils.copyProperties及Json序列化反序列化方式转换性能比较低(阿里巴巴规范检查有提示不建议采用). ...
- java 对象 转换 工具类_Java中excel与对象的互相转换的通用工具类编写与使用(基于apache-poi-ooxml)...
通用excel与对象相互转换的工具类 前言:最近开发需要一个Excel批量导入或者导出的功能,之前用过poi-ooxml开发过一个导入的工具类,正好蹭着这次机会,把工具类的功能进行完善. 使用说明: ...
- 【Java对象转换】003- Java 对象与 Yaml 互转
[Java对象转换]003- Java 对象与 Yaml 互转 文章目录 [Java对象转换]003- Java 对象与 Yaml 互转 一.Java 对象与 Yaml 概述 1.Java 对象 2. ...
- 【Java】json与java对象转换,获得数据库自增主键,保存返回数据 (个人梳理)
[Java]json与java对象转换,获得数据库自增主键,保存返回数据 (个人梳理) 模拟请求API 获得json数据,将json转换为java对象,再将java对象转换为list集合,再将list ...
- Java对象转换成JSON对象/JSON对象转换成JSON字符串/JSON字符串转换成JS对象
文章目录 后端部分 前端部分 后端部分 Option op = new Option("海淀","hd");//java对象转换json对象 JSONObjec ...
- gson转对象变成null_FastJson、Jackson、Gson进行Java对象转换Json的细节处理
转 https://blog.csdn.net/moneyshi/article/details/51830329 Java对象转换Json的细节处理 前言 Java对象在转json的时候,如果对象里 ...
- JAVA Bean 转换工具 BULL 使用简介
How to Transform Any Type of Java Bean With BULL 在跨团队或者跨系统的开发调用时,经常遇到 两个系统Java 代码命名不一致的情况,简单直接的办法就是写 ...
- 实现一个在JNI中调用Java对象的工具类,从此只需一行代码
前言 我们知道在jni中执行一个java函数需要调用几行代码才行,如 jclass objClass = (*env).GetObjectClass(obj); jmethodID methodID ...
- xml与java对象转换 -- XStreamAlias
@XStreamAlias使用 一. 特点: 简化的API; 无映射文件; 高性能,低内存占用; 整洁的XML; 不需要修改对象;支持内部私有字段,不需要setter/getter方法 提供 ...
最新文章
- window COM调试2[转]
- 1、一、Introduction(入门): 0、Introduction to Android(引进到Android)
- 计算机考试一年有肌肉,阅卷老师最想看到什么样的字体?电脑阅卷时代,这种字体很吃香...
- 西安理工大学计算机考研难吗,西安理工大学考研难吗?一般要什么水平才可以进入?...
- 数据结构课上笔记10
- Day13-日历模块
- 设计模式(3)--SimpleFactory( [1] 简单工厂模式)--创建型
- VALSE学习(十五):网络搜索结构-NAS
- 易辅客栈第一套从零学辅助系列教程
- 2020中兴捧月算法大赛——傅里叶赛道 第1名方案
- JPG图片怎么转换成Word文档
- php微信授权登录sdk,微信授权登录如何使用?总结微信授权登录实例用法
- Python py文件如何调用其他py文件
- 数据分析与挖掘(一)误差与精度
- 用手动Ghost重装系统(gho镜像)
- unity hub 免费版实现
- 每日一面 - MySQL 的双一设置是什么?
- 【机器学习之模型融合】Voting投票法简单实践
- 关于java操作zebraZT230打印机
- 计算机基础实验测试题第一章(悄悄变强秘籍)
热门文章
- Java简单的药店管理系统,实现添加,查询,修改,删除,打印药品信息
- 企业怎样做好网络营销中的论坛营销
- [机缘参悟-44]:鬼谷子-第八摩篇- 摩者,顺而抚之也, 摩得其情,则顺而抚之,以成其事.
- ios测试闪存用什么软件,TLC还是MLC?教你检测iPhone6闪存类型
- 数据源的定义以及配置
- python短信平台_Python短信接口demo
- python卷积计算_python scipy卷积运算的实现方法
- 「跑付」长沙健身服务中心响应全民健身计划,创造更好的运动环境
- 显示器接口_Mac 用户超好用的显示器,色彩完美还接口多
- 商品服务3-三级分类-查询展示三级分类数据