声明:
本文参考文章:
https://blog.csdn.net/datastructure18/article/details/120208842
https://blog.csdn.net/qq_44732146/article/details/119968376
一、背景
前两天,有个新同事问了我一个用mapstruct转换对象的问题。具体问题是这样的,对象里面包含做一个list,list里面的实体是该对象的内部类。因为不了解这块,一时间回答不了,于是上网查点资料研究研究。
二、mapstruct简介
Mapstruct一种实体类映射框架,能够通过Java注解将一个实体类的属性安全地赋值给另一个实体类。只需要定义一个映射器接口,声明需要映射的方法,在编译过程中,mapstruct会自动生成该接口的实现类,实现将源对象映射到目标对象的效果。
三、mapstruct与其他映射框架对比
实体类映射框架大致有两种:一种是运行期通过java反射机制动态映射;另一种是编译期动态生成getter/setter,在运行期直接调用框架编译好的class类实现实体映射。
由于mapstruct映射是在编译期间实现的,因此相比运行期的映射框架有以下几个优点:
1、 安全性高。
因为是编译期就实现源对象到目标对象的映射,如果编译器能够通过,运行期就不会报错;
2、 速度快。
速度快指的是运行期间直接调用实现类的方法,不会在运行期间使用反射进行转化。
四、mapstruct包分析、
Mapstruct主要有两个包:
1、 org.mapstruct:mapstruct:包含了映射相关的注解,如@Mapper、@Mapping等。
2、 org.mapstruct:mapstruct-processor:包含了注解处理器。用于处理注解相关的逻辑,如MappingProcessor等。
五、mapstruct配置
1、maven依赖:
org.projectlombok
lombok
1.16.16
org.mapstruct
mapstruct
1.3.1.Final
org.mapstruct
mapstruct-processor
1.3.1.Final
2、相关插件:
安装mapstruct support后,在参数上按ctrl+左键,能够自动进入参数所在类文件,亲测好用。
3、 在pom文件中加入binding插件:
pom.xml -> build-> plugins 下加入 lombok-mapstruct-binding
org.apache.maven.plugins
maven-compiler-plugin
3.5.1
1.8
org.mapstruct
mapstruct-processor
1.3.1.Final
org.projectlombok
lombok
1.18.20
org.projectlombok
lombok-mapstruct-binding
0.2.0
用来解决:Error:(15, 13) java: No property named “id“ exists in source parameter(s). Did you mean “null“?
4、 本地启动增加参数:
Settings -> Build,Execution,Deployment -> Compiler 下,选择 User-local build process VM options (overrides Shared options):
添加参数
-Djps.track.ap.dependencies=false
六、代码实例:
package com.xld.test.mapstruct;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SourceObject {
private String sourceName;
private SourceAddrInfo sourceAddrInfo;
private List sourceDetailInfoList;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SourceAddrInfo{
private String sourceAddr;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SourceDetailInfo{
private String sourceDetail;
}
}
package com.xld.test.mapstruct;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TargetObject {
private String targetName;
private TargetAddrInfo targetAddrInfo;
private List targetDetailInfoList;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class TargetAddrInfo{
private String targetAddr;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class TargetDetailInfo{
private String targetDetail;
}
}
package com.xld.test.mapstruct;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
@Mapper
public interface BuilderConverter {
BuilderConverter INSTANCE = Mappers.getMapper(BuilderConverter.class);
@Mapping(source = "sourceName",target = "targetName")
TargetObject converterParam(SourceObject sourceObject);
@Mapping(source = "sourceAddr",target = "targetAddr")
TargetObject.TargetAddrInfo converterAddrInfo(SourceObject.SourceAddrInfo sourceAddrInfo);
@Mapping(source = "sourceDetail",target = "targetDetail")
TargetObject.TargetDetailInfo converterDetailInfo(SourceObject.SourceDetailInfo sourceDetailInfo);
@Mappings({
@Mapping(source = "sourceName",target = "targetName"),
@Mapping(source = "sourceAddrInfo",target = "targetAddrInfo"),
@Mapping(source = "sourceDetailInfoList",target = "targetDetailInfoList")
})
TargetObject converterObjectMappings(SourceObject sourceObject);
public static void main(String[] args) {
SourceObject sourceObject = SourceObject.builder()
.sourceName("sourceName")
.build();
TargetObject targetObject = INSTANCE.converterParam(sourceObject);
System.out.println("---------验证单个参数----------");
System.out.println(sourceObject);
System.out.println(targetObject);
SourceObject.SourceAddrInfo sourceAddrInfo = SourceObject.SourceAddrInfo.builder()
.sourceAddr("sourceAddr")
.build();
TargetObject.TargetAddrInfo targetAddrInfo = INSTANCE.converterAddrInfo(sourceAddrInfo);
System.out.println("---------验证Addr对象----------");
System.out.println(sourceAddrInfo);
System.out.println(targetAddrInfo);
SourceObject.SourceDetailInfo sourceDetailInfo = SourceObject.SourceDetailInfo.builder()
.sourceDetail("sourceDetail")
.build();
TargetObject.TargetDetailInfo targetDetailInfo = INSTANCE.converterDetailInfo(sourceDetailInfo);
System.out.println("---------验证Detail对象----------");
System.out.println(sourceDetailInfo);
System.out.println(targetDetailInfo);
List sourceDetailInfoList = new ArrayList<>();
sourceDetailInfoList.add(SourceObject.SourceDetailInfo.builder()
.sourceDetail("sourceDetail1")
.build());
sourceDetailInfoList.add(SourceObject.SourceDetailInfo.builder()
.sourceDetail("sourceDetail2")
.build());
sourceObject = SourceObject.builder()
.sourceName("sourceName")
.sourceAddrInfo(sourceAddrInfo)
.sourceDetailInfoList(sourceDetailInfoList)
.build();
sourceObject.setSourceAddrInfo(sourceAddrInfo);
targetObject = INSTANCE.converterObjectMappings(sourceObject);
System.out.println("----------验证整个对象---------");
System.out.println(sourceObject);
System.out.println(targetObject);
}
}
执行结果:
---------验证单个参数----------
SourceObject(sourceName=sourceName, sourceAddrInfo=null, sourceDetailInfoList=null)
TargetObject(targetName=sourceName, targetAddrInfo=null, targetDetailInfoList=null)
---------验证Addr对象----------
SourceObject.SourceAddrInfo(sourceAddr=sourceAddr)
TargetObject.TargetAddrInfo(targetAddr=sourceAddr)
---------验证Detail对象----------
SourceObject.SourceDetailInfo(sourceDetail=sourceDetail)
TargetObject.TargetDetailInfo(targetDetail=sourceDetail)
----------验证整个对象---------
SourceObject(sourceName=sourceName, sourceAddrInfo=SourceObject.SourceAddrInfo(sourceAddr=sourceAddr), sourceDetailInfoList=[SourceObject.SourceDetailInfo(sourceDetail=sourceDetail1), SourceObject.SourceDetailInfo(sourceDetail=sourceDetail2)])
TargetObject(targetName=sourceName, targetAddrInfo=TargetObject.TargetAddrInfo(targetAddr=sourceAddr), targetDetailInfoList=[TargetObject.TargetDetailInfo(targetDetail=sourceDetail1), TargetObject.TargetDetailInfo(targetDetail=sourceDetail2)])