1. 简介

lamia 是一个高性能的Java 实体映射工具, 使用简单的注解就能帮助你在编译期生成对应的转换代码

项目地址:

  • github
  • gitee

1.1 优势

  • 方便灵活的编译期快速生成转换代码
  • 支持和lombokAnnotationProcessor框架同时使用
  • 支持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> nameString 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对象转换工具相关推荐

  1. 自定义java对象转换工具类

    背景 项目中经常有VO.PO.DTO等之间转换,由于apache工具类中BeanUtils.copyProperties及Json序列化反序列化方式转换性能比较低(阿里巴巴规范检查有提示不建议采用). ...

  2. java 对象 转换 工具类_Java中excel与对象的互相转换的通用工具类编写与使用(基于apache-poi-ooxml)...

    通用excel与对象相互转换的工具类 前言:最近开发需要一个Excel批量导入或者导出的功能,之前用过poi-ooxml开发过一个导入的工具类,正好蹭着这次机会,把工具类的功能进行完善. 使用说明: ...

  3. 【Java对象转换】003- Java 对象与 Yaml 互转

    [Java对象转换]003- Java 对象与 Yaml 互转 文章目录 [Java对象转换]003- Java 对象与 Yaml 互转 一.Java 对象与 Yaml 概述 1.Java 对象 2. ...

  4. 【Java】json与java对象转换,获得数据库自增主键,保存返回数据 (个人梳理)

    [Java]json与java对象转换,获得数据库自增主键,保存返回数据 (个人梳理) 模拟请求API 获得json数据,将json转换为java对象,再将java对象转换为list集合,再将list ...

  5. Java对象转换成JSON对象/JSON对象转换成JSON字符串/JSON字符串转换成JS对象

    文章目录 后端部分 前端部分 后端部分 Option op = new Option("海淀","hd");//java对象转换json对象 JSONObjec ...

  6. gson转对象变成null_FastJson、Jackson、Gson进行Java对象转换Json的细节处理

    转 https://blog.csdn.net/moneyshi/article/details/51830329 Java对象转换Json的细节处理 前言 Java对象在转json的时候,如果对象里 ...

  7. JAVA Bean 转换工具 BULL 使用简介

    How to Transform Any Type of Java Bean With BULL 在跨团队或者跨系统的开发调用时,经常遇到 两个系统Java 代码命名不一致的情况,简单直接的办法就是写 ...

  8. 实现一个在JNI中调用Java对象的工具类,从此只需一行代码

    前言 我们知道在jni中执行一个java函数需要调用几行代码才行,如 jclass objClass = (*env).GetObjectClass(obj); jmethodID methodID ...

  9. xml与java对象转换 -- XStreamAlias

    @XStreamAlias使用 一. 特点: 简化的API;  无映射文件;  高性能,低内存占用;  整洁的XML;  不需要修改对象;支持内部私有字段,不需要setter/getter方法  提供 ...

最新文章

  1. window COM调试2[转]
  2. 1、一、Introduction(入门): 0、Introduction to Android(引进到Android)
  3. 计算机考试一年有肌肉,阅卷老师最想看到什么样的字体?电脑阅卷时代,这种字体很吃香...
  4. 西安理工大学计算机考研难吗,西安理工大学考研难吗?一般要什么水平才可以进入?...
  5. 数据结构课上笔记10
  6. Day13-日历模块
  7. 设计模式(3)--SimpleFactory( [1] 简单工厂模式)--创建型
  8. VALSE学习(十五):网络搜索结构-NAS
  9. 易辅客栈第一套从零学辅助系列教程
  10. 2020中兴捧月算法大赛——傅里叶赛道 第1名方案
  11. JPG图片怎么转换成Word文档
  12. php微信授权登录sdk,微信授权登录如何使用?总结微信授权登录实例用法
  13. Python py文件如何调用其他py文件
  14. 数据分析与挖掘(一)误差与精度
  15. 用手动Ghost重装系统(gho镜像)
  16. unity hub 免费版实现
  17. 每日一面 - MySQL 的双一设置是什么?
  18. 【机器学习之模型融合】Voting投票法简单实践
  19. 关于java操作zebraZT230打印机
  20. 计算机基础实验测试题第一章(悄悄变强秘籍)

热门文章

  1. Java简单的药店管理系统,实现添加,查询,修改,删除,打印药品信息
  2. 企业怎样做好网络营销中的论坛营销
  3. [机缘参悟-44]:鬼谷子-第八摩篇- 摩者,顺而抚之也, 摩得其情,则顺而抚之,以成其事.
  4. ios测试闪存用什么软件,TLC还是MLC?教你检测iPhone6闪存类型
  5. 数据源的定义以及配置
  6. python短信平台_Python短信接口demo
  7. python卷积计算_python scipy卷积运算的实现方法
  8. 「跑付」长沙健身服务中心响应全民健身计划,创造更好的运动环境
  9. 显示器接口_Mac 用户超好用的显示器,色彩完美还接口多
  10. 商品服务3-三级分类-查询展示三级分类数据