亲宝软件园·资讯

展开

MapStruct解决Bean属性拷贝

心城以北 人气:3

简介

MapStruct 是一个代码生成器(可以生成对象映射转换的代码),它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现。

生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。

适用场景

多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射。编写这样的映射代码是一项乏味且容易出错的任务。MapStruct 旨在通过尽可能地自动化来简化这项工作。

与其他映射框架相比,MapStruct 在编译时生成 bean 映射,这确保了高性能,允许快速的开发人员反馈和彻底的错误检查。

说白了就解决 beanCopy 的问题。

工作时机

MapStruct 是一个注解处理器,它插入到 Java 编译器中,可用于命令行构建(Maven、Gradle 等)以及您首选的 IDE。

MapStruct 使用合理的默认值,但在配置或实现特殊行为时会采取措施。

使用案例

1、添加依赖

// mapstruct
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
复制代码

2、定义两个类

一个 Car 类(JPA 实体类)

一个 CarDto 类(数据传输类)

这两个类型非常相似,只是在计数属性的字段名不同,并且 type 属性是 CarType 枚举类型,CarDto 中是字符串类型。

Car 类

public class Car {
    private String make;
    private int numberOfSeats;
    private CarType type;
    //constructor, getters, setters etc.
}

CarType 类定义

public enum CarType {
    SEDAN;
}

CarDto 类

public class CarDto {
    private String make;
    private int seatCount;
    private String type; 
    //constructor, getters, setters etc.
}

创建转换器类接口,定义需要将 Car 对象转换为 CarDto 对象

@Mapper
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}

1). @Mapper 注解将该接口标记为映射接口,并且让 MapStruct 处理器在编译期间进行处理,实际映射方法为 carToCarDto 目的就是原参数Car,转换为方法返回结果对象 CarDto

2). 对于源对象和目标对象中有不同的属性名称,我们可以使用 @Mapping 注解进行映射。在默认情况下,将源对象和目标对象据欧不同的类型属性执行类型转换,例如,type 数据原来是枚举,可以自动转换为字符串。

3). 以一个 Mapper 接口也支持多个映射方法。所有的这些方法都由 MapStruct 框架来实现。我们可以从 Mappers类中检索接口实现的实例。通常我们在接口中申明一个 INSTANCE 属性,提供对外访问的实例。

3、单元测试

@Test
public void shouldMapCarToDto () {
    //given
    Car car = new Car("Morris", 5, CarType.SEDAN);
    //when
    CarDto carDto = CarMapper.INSTANCE.carToCarDto(car);
    //then
    assertThat(carDto).isNotNull();
    assertThat(carDto.getMake()).isEqualTo("Morris");
    assertThat(carDto.getSeatCount()).isEqualTo(5);
    assertThat(carDto.getType()).isEqualTo("SEDAN");
}

我们使用起来就是非常简单,运行结果如下:

核心总结

MapStruct其实和 Lombok 有些类似,也是通过插件的方式在我们编译期为我们生成一些辅助的代码。但是MapStruct 专注是解决 BeanCopy 以及对象转换的场景。

下面我们看看,就是我们 CarMapper 的实现类 CarMapperImpl , 这些都是框架在编译期间,我们生成的代码。

如果我们使用 BeanUtils.copyProperties来做对象的转换是需要通过反射来获取对象的属性,方法等信息。然后再去赋值。反射虽然能够解决一些通用性的场景,但是对于频繁的 List 复制,性能是不高的。我们可以看看下面copyProperties的部分代码截图:

个人觉得 MapStruct的优势还是非常明显的,就是帮助我们少写了非常多的 getters, setters 进行对象的相互转换,性能高于任何一种属性复制。缺点就会降低程序编译速度,增加转换层提升代码复杂度。

参考文档

加载全部内容

相关教程
猜你喜欢
用户评论