你还在用 BeanUtils?试试 MapStruct,优雅的对象转换解决方案

简介: 你还在用 BeanUtils?试试 MapStruct,优雅的对象转换解决方案

第一次看到 MapStruct 的时候, 我个人非常的开心。因为其跟我内心里面的想法不谋而合。

 

1 MapStruct 是什么?

 

1.1 JavaBean 的困扰

 

对于代码中 JavaBean之间的转换, 一直是困扰我很久的事情。

 

在开发的时候我看到业务代码之间有很多的 JavaBean 之间的相互转化, 非常的影响观感, 却又不得不存在。我后来想的一个办法就是通过反射, 或者自己写很多的转换器。

 

第一种通过反射的方法确实比较方便, 但是现在无论

是 BeanUtils, BeanCopier 等在使用反射的时候都会影响到性能。虽然我们可以进行反射信息的缓存来提高性能。

 

但是像这种的话, 需要类型和名称都一样才会进行映射, 有很多时候, 由于不同的团队之间使用的名词不一样, 还是需要很多的手动 set/get 等功能。

 

第二种的话就是会很浪费时间, 而且在添加新的字段的时候也要进行方法的修改。不过, 由于不需要进行反射, 其性能是很高的。

 

1.2 MapStruct 带来的改变

 

MapSturct 是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)。

 

抓一下重点:

 

  1. 注解处理器
  2. 可以生成 JavaBean 之间那的映射代码
  3. 类型安全, 高性能, 无依赖性

 

从字面的理解, 我们可以知道, 该工具可以帮我们实现 JavaBean 之间的转换, 通过注解的方式。

 

同时, 作为一个工具类,相比于手写, 其应该具有便捷, 不容易出错的特点。

 

2 MapStruct 入门

 

入门很简单。我是基于 Maven 来进行项目 jar 包管理的。

 

2.1 引入依赖

 

 
        1.3.0.Final
 
 
 
    org.mapstruct
    mapstruct-jdk8
    ${org.mapstruct.version}
 
 
 
    org.mapstruct
    mapstruct-processor
    ${org.mapstruct.version}
 

 

2.2 创建entity和dto对象

 

该类是从 github 某个订单系统里面拿下来的部分。

 

@Data
public class Order {
 
    /**
     *订单id
     */
    private Long id;
 
    /**
     * 订单编号
     */
    private String orderSn;
 
    /**
     * 收货人姓名/号码
     */
    private String receiverKeyword;
 
    /**
     * 订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单
     */
    private Integer status;
 
    /**
     * 订单类型:0->正常订单;1->秒杀订单
     */
    private Integer orderType;
 
    /**
     * 订单来源:0->PC订单;1->app订单
     */
    private Integer sourceType;
}

 

对应的查询参数

 

@Data
public class OrderQueryParam {
    /**
     * 订单编号
     */
    private String orderSn;
 
    /**
     * 收货人姓名/号码
     */
    private String receiverKeyword;
 
    /**
     * 订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单
     */
    private Integer status;
 
    /**
     * 订单类型:0->正常订单;1->秒杀订单
     */
    private Integer orderType;
 
    /**
     * 订单来源:0->PC订单;1->app订单
     */
    private Integer sourceType;
 
 
}

 

2.3 写 Mapper

 

Mapper 即映射器, 一般来说就是写 xxxMapper 接口。

 

当然, 不一定是以 Mapper 结尾的。只是官方是这么写的。在本入门例子中,对应的接口如下

 

import com.homejim.mapstruct.dto.OrderQueryParam;
import com.homejim.mapstruct.entity.Order;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
 
@Mapper
public interface OrderMapper {
 
    OrderQueryParam entity2queryParam(Order order);
 
}
 

 

简单的映射(字段和类型都匹配), 只有一个要求, 在接口上写@Mapper 注解即可。

 

然后方法上, 入参对应要被转化的对象, 返回值对应转化后的对象, 方法名称可任意。

 

2.4 测试

 

写一个测试类测试一下。

 

@Test
public void entity2queryParam() {
    Order order = new Order();
    order.setId(12345L);
    order.setOrderSn("orderSn");
    order.setOrderType(0);
    order.setReceiverKeyword("keyword");
    order.setSourceType(1);
    order.setStatus(2);
 
    OrderMapper mapper = Mappers.getMapper(OrderMapper.class);
    OrderQueryParam orderQueryParam = mapper.entity2queryParam(order);
    assertEquals(orderQueryParam.getOrderSn(), order.getOrderSn());
    assertEquals(orderQueryParam.getOrderType(), order.getOrderType());
    assertEquals(orderQueryParam.getReceiverKeyword(), order.getReceiverKeyword());
    assertEquals(orderQueryParam.getSourceType(), order.getSourceType());
    assertEquals(orderQueryParam.getStatus(), order.getStatus());
 
}

 

测试通过, 没有任何的问题。

 

3 MapStruct 分析

 

上面中, 我写了3个步骤来实现了从 Order 到 OrderQueryParam 的转换。

 

那么, 作为一个注解处理器, 通过MapStruct 生成的代码具有怎么样的优势呢?

 

3.1 高性能

 

这是相对反射来说的, 反射需要去读取字节码的内容, 花销会比较大。学反射看《Java反射看这篇绝对会了》这篇够了!

 

而通过 MapStruct 来生成的代码, 其类似于人手写。速度上可以得到保证。

 

前面例子中生成的代码可以在编译后看到。在 target/generated-sources/annotations 里可以看到。

 

生成的代码

 

对应的代码

 

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-08-02T00:29:49+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 11.0.2 (Oracle Corporation)"
)
public class OrderMapperImpl implements OrderMapper {
 
    @Override
    public OrderQueryParam entity2queryParam(Order order) {
        if ( order == null ) {
            return null;
        }
 
        OrderQueryParam orderQueryParam = new OrderQueryParam();
 
        orderQueryParam.setOrderSn( order.getOrderSn() );
        orderQueryParam.setReceiverKeyword( order.getReceiverKeyword() );
        orderQueryParam.setStatus( order.getStatus() );
        orderQueryParam.setOrderType( order.getOrderType() );
        orderQueryParam.setSourceType( order.getSourceType() );
 
        return orderQueryParam;
    }
}
 

 

可以看到其生成了一个实现类, 而代码也类似于我们手写, 通俗易懂。

 

3.2 易于 debug

 

在我们生成的代码中, 我们可以轻易的进行 debug。

 

 

 

 

易于 DEBUG

 

 

在使用反射的时候, 如果出现了问题, 很多时候是很难找到是什么原因的。

 

3.3 使用相对简单

 

如果是完全映射的, 使用起来肯定没有反射简单。

 

用类似 BeanUtils 这些工具一条语句就搞定了。但是,如果需要进行特殊的匹配(特殊类型转换, 多对一转换等), 其相对来说也是比较简单的。

 

基本上, 使用的时候, 我们只需要声明一个接口, 接口下写对应的方法, 就可以使用了。当然, 如果有特殊情况, 是需要额外处理的。

 

3.4 代码独立

 

生成的代码是对立的, 没有运行时的依赖。

相关文章
|
6月前
|
Java Maven 开发工具
【mapstruct】Java 中 mapstruct mapper 转换器部分字段转换无效的解决方案
【mapstruct】Java 中 mapstruct mapper 转换器部分字段转换无效的解决方案
163 0
MapStruct - 生成空对象解决方案
MapStruct - 生成空对象解决方案
811 0
|
8月前
|
安全 Java Maven
使用MapStruct简化Java对象映射
在软件开发中,经常需要将一个Java对象的数据映射到另一个对象,特别是在使用DTO(Data Transfer Object)模式时。手动编写这些映射代码非常繁琐,而MapStruct可以帮助我们自动生成这些映射代码,从而提高开发效率和代码质量。
170 2
|
4月前
|
Java Apache Spring
Spring BeanUtils 2、Cglib BeanCopier 3、Apache BeanUtils 4、Apache PropertyUtils 5、Dozer 那么,我们到底应该选择哪种工具类更加合适呢?为什么Java开发手册中提到禁止使用Apache BeanUtils呢
Spring BeanUtils 2、Cglib BeanCopier 3、Apache BeanUtils 4、Apache PropertyUtils 5、Dozer 那么,我们到底应该选择哪种工具类更加合适呢?为什么Java开发手册中提到禁止使用Apache BeanUtils呢
61 0
|
6月前
|
Java
【MapStruct】引入MapStruct之后,项目启动java:找不到符号
【MapStruct】引入MapStruct之后,项目启动java:找不到符号
47 0
|
8月前
|
Java 数据库连接 数据库
解析 Java 中的 @Mapper 注解:优雅实现对象映射的高效利器
在现代软件开发中,对象映射是一个常见的任务,而 Java 中的 `@Mapper` 注解则是实现对象映射的强大工具。通过该注解,我们可以轻松地定义对象之间的映射关系,提高代码的可读性和可维护性。本文将带您深入探索 Java 中的 `@Mapper` 注解,揭示其作用、用法以及在实际开发中的应用场景。
|
JSON Java fastjson
阿粉带你彻底解决开发中对象Bean与Map互转问题!
在实际开发过程中,经常碰到需要进行对象与map之间互转的问题,其实对于对象、Map 之间进行互转有很多种方式,下面我们一起来梳理一下:
1073 0
阿粉带你彻底解决开发中对象Bean与Map互转问题!
性能高、上手快,实体类转换工具 MapStruct 到底有多强大
1.什么是MapStruct 1.1 JavaBean 的困扰 对于代码中 JavaBean之间的转换, 一直是困扰我很久的事情。在开发的时候我看到业务代码之间有很多的 JavaBean 之间的相互转化, 非常的影响观感,却又不得不存在。我后来想的一个办法就是通过反射,或者自己写很多的转换器。 第一种通过反射的方法确实比较方便,但是现在无论是 BeanUtils, BeanCopier 等在使用反射的时候都会影响到性能。虽然我们可以进行反射信息的缓存来提高性能。但是像这种的话,需要类型和名称都一样才会进行映射,有很多时候,由于不同的团队之间使用的名词不一样,还是需要很多的手动 set/get
|
XML Java 数据格式
建造者模式实例数据拼接 java生成真实XML文件
建造者模式实例数据拼接 java生成真实XML文件
113 0
建造者模式实例数据拼接 java生成真实XML文件
|
安全 IDE Java
MapStruct 解决 Bean 属性拷贝性能问题
无意间看到项目中有小伙伴用到了 MapStruct 来做对象映射转换当时我就很好奇,这个是什么框架,能够解决什么问题,带着这两个疑问就有了下面的文章。
281 0
MapStruct 解决 Bean 属性拷贝性能问题