项目中用到对象拷贝,做一个修改历史记录保存的功能,使用Spring AOP自定义注解实现修改记录的保存,历史记录表和业务表的字段差不多,保存的时候需要用到对象拷贝。下面是一些对象拷贝的工具,前3个都用过,这次想尝试一下新的mapstruct,喜新厌旧一波。
1. 对象拷贝常见的工具类
1.1 Apache 的BeanUtils的copyProperties方法
特点:浅拷贝,属性还是指向原本对象的引用。字段名称相同,类型不同无法进行赋值,基本类型字段和引用对象可以映射。
1.2 SpringUtils的copyProperties方法
特点:同Apache,效率比Apache高,参数的位置与Apache不同
1.3 序列化(JSON)
特点:深拷贝,性能低,耗时长(序列化-反序列化)。基本类和引用对象可以映射。字段名称相同,类型不同可以赋值。
1.4 MapStruct
特点:深拷贝,灵活(可自主配置字段映射关系),可以配置多对一映射关系。效率高,准确(编译器代码生成,源码就是get、set方法)。
2. MapStruct初次使用配置过程
2.1典型的常规操作,这里记录我配置过程中遇到的问题,仅供参考,可以不看,直接看后面的正确配置;
2.2决定要用,就先Bing了一把,大体一看内容还算完整,有配置,有测试,还有代码和源码,一看感觉不难,哐哐哐一顿配置,然后不出意外的报错了;
2.3我用的是公司封装的框架,耦合高,有几点和网上说的不一样:
一个是我的实体类有继承;
二个是我继承的实体类没有用lombok插件,我用了;
这两点对我造成了困扰,但是不影响使用MapStruct。
遇到的异常有:
一个是“No property named “XXX“ exists in source parameter(s). Did you mean news”;
No property named “XXX“ exists in source parameter(s). Did you mean news一个是lombok插件的问题,提示java找不到符号(解决第一个问题过程中,越解决问题越严重);
2.4配置过程
一开始,导入maven依赖,根据网上的博文,注意lombok和mapstruct的版本,选择了同一个年份的版本。这里我用的是lombok插件,查看版本后选择的mapstruct版本,发布的年份一样,但是月份不一样,就配置上了。
然后就可以添加代码,写了Mapper和拷贝方法,就开始单元测试,问题来了,提示No property named “XXX“ exists in source parameter(s),虽然属性我可以点进去,但是就是报错。我怀疑是版本问题,就开始重新捣鼓版本,各种尝试,没解决。只好去官网,发现官网上的配置还添加了maven-compiler-plugin插件,我也加上,然而问题更严重了,冲突更厉害,直接影响我的lombok代码,改了3个d插的件版本,未解决,只能还原回去,确认就是版本问题。因为MapStruct原理类似于lombok,都是在编译期进行实现。只能继续看官网文档,最终配置成功。有问题找官网准没错。
3. MapStruct的正确配置,这里介绍maven方式
3.1项目pom文件添加依赖和plugins
<properties>
    <java.version>1.8</java.version>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
    <org.projectlombok.version>1.18.26</org.projectlombok.version>
    <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties><dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>${org.projectlombok.version}</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>${org.mapstruct.version}</version>
</dependency><plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.11.0</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>${org.mapstruct.version}</version>
            </path>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${org.projectlombok.version}</version>
            </path>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok-mapstruct-binding</artifactId>
                <version>${lombok-mapstruct-binding.version}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>3.2编写Mapper,我这里就用官网的代码了
CarMapper.java
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
@Mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToCarDto(Car car);
}
Car.java
public class Car {
    private String make;
    private int numberOfSeats;
    private CarType type;
    //constructor, getters, setters etc.
}
CatDto.java
public class CarDto {
    private String make;
   private int seatCount;
    private String type;
    //constructor, getters, setters etc.
}
测试方法:
@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" );
}
4.总结:初次使用,没啥经验总结,这个项目也是简单使用,如有机会再深入了解。
4.1 lombok版本和MapStruct版本可以不必严格保持时间上对应。我这里用的就是最新的MapStruct版本和我IDE中lombok的插件版本,并不冲突。
4.2 如果两个对象中变量命名一致可以不用配置@Mapping。
/**
     * 这个方法就是用于实现对象属性复制的方法
     *
     * @param xx 这个参数就是源对象,也就是需要被复制的对象
     * @return 返回的是目标对象,就是最终的结果对象
     * @Mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性
     */
    @Mappings({@Mapping(source = "id", target = "detailId")})4.3有事找官网
官网:MapStruct – Java bean mappings, the easy way!
再不行找官网的例子:
GitHub - mapstruct/mapstruct-examples: Examples for using MapStruct
4.4 maven-compiler-plugin插件的版本根据你自己需要选择,不影响。主要的是annotationProcessorPaths的配置,我参考的是官方例子里面的mapstruct-lombok。











![[数据集][目标检测]遛狗不牵绳数据集VOC格式-1980张](https://i0.hdslb.com/bfs/archive/b218ed1884b250be57b2ee3ae09d26814eb427c8.jpg@100w_100h_1c.png@57w_57h_1c.png)







