mapstract实体转换工具
什么mapSturct
mapSturct
是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)。通过动态生成代码实现,使代码易于调试和美观,
官方文档:https://mapstruct.org/documentation/stable/reference/html/#mapping-composition
引入POM
<properties> <org.mapstruct.version>1.2.0.CR1</org.mapstruct.version> </properties> <dependencies> <!--mapStruct依赖--> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-jdk8</artifactId> <version>${org.mapstruct.version}</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> <scope>provided</scope> </dependency> </dependencies>
简单使用
@Mapper public interface PurchasePayableBillConvert { PurchasePayableBillConvert INSTANCE = Mappers.getMapper(PurchasePayableBillConvert.class); BillAdjustTypeItemSumDTO toBillAdjustTypeItemSumDTO(PurchasePayableBillAdjustLogDTO purchasePayableBillAdjustLogDTO); List<BillAdjustTypeItemSumDTO> toBillAdjustTypeItemSumDTOs(List<PurchasePayableBillAdjustLogDTO> purchasePayableBillAdjustLogDTOs); BillAdjustTypeItemSumDTO toBillAdjustTypeItemSumDTO(PurchasePayableBillAdjustLog purchasePayableBillAdjustLog); }
与Spring整合
//此注解在自动生成实现类会打上@Comment注解 我们只需要让Spring扫描就行了 @Mapper(componentModel = "spring") public interface MemberGradeConvert {
public MemberGradeEntity editReqDtOToPo(EditReqDtO editReqDtO); }
以上面为例自动在targer目录生成实现类
@Component public class MemberGradeConvertImpl implements MemberGradeConvert { public MemberGradeConvertImpl() { } public MemberGradeEntity editReqDtOToPo(EditReqDtO editReqDtO) { if (editReqDtO == null) { return null; } else { MemberGradeEntity memberGradeEntity = new MemberGradeEntity(); memberGradeEntity.setId(editReqDtO.getId()); memberGradeEntity.setName(editReqDtO.getName()); memberGradeEntity.setPoints(editReqDtO.getPoints()); memberGradeEntity.setDiscountRate(editReqDtO.getDiscountRate()); memberGradeEntity.setStatus(editReqDtO.getStatus()); memberGradeEntity.setMerchantId(editReqDtO.getMerchantId()); return memberGradeEntity; } } }
多个组成一个VO
@Mapper(componentModel = "spring") public interface CouponConvert { @Mapping(source = "couponCode.id", target = "couponCodeId") @Mapping(source = "couponCode.used", target = "used") @Mapping(source = "couponCode.usedDate", target = "usedDate") @Mapping(source = "couponCode.receiveDate", target = "receiveDate") @Mapping(source = "couponRo.enable", target = "enable") @Mapping( target = "expireDate",expression = "java(CouponConvert.getMaxDate(couponCode.getUsageEndDate(), couponRo==null?null:couponRo.getUsageEndDate()))") public FindUserCouponsResDto couponCodeAndCouponRoToFindUserCouponsResDto(CouponCode couponCode, CouponRo couponRo); static Timestamp getMaxDate(Timestamp date1, Timestamp date2){ if(date1==null){ return date2; } if(date2==null){ return date1; } return date1.getTime()>date2.getTime()?date1:date2; } }
自动生成实现
@Component public class CouponConvertImpl implements CouponConvert { @Override public FindUserCouponsResDto couponCodeAndCouponRoToFindUserCouponsResDto(CouponCode couponCode, CouponRo couponRo) { if ( couponCode == null && couponRo == null ) { return null; } FindUserCouponsResDto findUserCouponsResDto = new FindUserCouponsResDto(); if ( couponCode != null ) { findUserCouponsResDto.setCouponCodeId( couponCode.getId() ); findUserCouponsResDto.setReceiveDate( couponCode.getReceiveDate() ); findUserCouponsResDto.setUsedDate( couponCode.getUsedDate() ); findUserCouponsResDto.setUsed( couponCode.isUsed() ); } if ( couponRo != null ) { if ( couponRo.getEnable() != null ) { findUserCouponsResDto.setEnable( couponRo.getEnable() ); } } findUserCouponsResDto.setExpireDate( CouponConvert.getMaxDate(couponCode.getUsageEndDate(), couponRo==null?null:couponRo.getUsageEndDate()) ); return findUserCouponsResDto; } }
简单的条件处理
@Mapping(source = "couponCode.id", target = "couponCodeId") @Mapping(source = "couponCode.used", target = "used") @Mapping(source = "couponCode.usedDate", target = "usedDate") @Mapping(source = "couponCode.receiveDate", target = "receiveDate") @Mapping(source = "couponRo.enable", target = "enable") @Mapping(target = "amount", expression = "java(couponCode.getRanAmount()!=null?couponCode.getRanAmount():couponRo.getAmount())") @Mapping(target = "expireDate", expression = "java(couponRo.getUsageCountDownDays()!=null?couponCode.getUsageEndDate():couponRo.getUsageEndDate())") public FindUserCouponCodeByIdResDto couponCodeRoAndCouponRoToFindUserCouponCodeByIdResDto(CouponCodeRo couponCode, CouponRo couponRo);
转换后
@Override public FindUserCouponCodeByIdResDto couponCodeRoAndCouponRoToFindUserCouponCodeByIdResDto(CouponCodeRo couponCode, CouponRo couponRo) { if ( couponCode == null && couponRo == null ) { return null; } FindUserCouponCodeByIdResDto findUserCouponCodeByIdResDto = new FindUserCouponCodeByIdResDto(); if ( couponCode != null ) { findUserCouponCodeByIdResDto.setCouponCodeId( couponCode.getId() ); findUserCouponCodeByIdResDto.setReceiveDate( couponCode.getReceiveDate() ); findUserCouponCodeByIdResDto.setUsedDate( couponCode.getUsedDate() ); findUserCouponCodeByIdResDto.setUsed( couponCode.isUsed() ); } if ( couponRo != null ) { findUserCouponCodeByIdResDto.setEnable( couponRo.getEnable() ); } findUserCouponCodeByIdResDto.setAmount( couponCode.getRanAmount()!=null?couponCode.getRanAmount():couponRo.getAmount() ); findUserCouponCodeByIdResDto.setExpireDate( couponRo.getUsageCountDownDays()!=null?couponCode.getUsageEndDate():couponRo.getUsageEndDate() ); return findUserCouponCodeByIdResDto; } }
复杂的表达式
@Mapper(componentModel = "spring") public interface CouponConvert { @Mapping(source = "couponCode.id", target = "couponCodeId") @Mapping(source = "couponCode.used", target = "used") @Mapping(source = "couponCode.usedDate", target = "usedDate") @Mapping(source = "couponCode.receiveDate", target = "receiveDate") @Mapping(source = "couponRo.enable", target = "enable") @Mapping( target = "expireDate",expression = "java(CouponConvert.getMaxDate(couponCode.getUsageEndDate(), couponRo==null?null:couponRo.getUsageEndDate()))") public FindUserCouponsResDto couponCodeAndCouponRoToFindUserCouponsResDto(CouponCode couponCode, CouponRo couponRo); static Timestamp getMaxDate(Timestamp date1, Timestamp date2){ if(date1==null){ return date2; } if(date2==null){ return date1; } return date1.getTime()>date2.getTime()?date1:date2; } }
转换后
@Component public class CouponConvertImpl implements CouponConvert { @Override public FindUserCouponsResDto couponCodeAndCouponRoToFindUserCouponsResDto(CouponCode couponCode, CouponRo couponRo) { if ( couponCode == null && couponRo == null ) { return null; } FindUserCouponsResDto findUserCouponsResDto = new FindUserCouponsResDto(); if ( couponCode != null ) { findUserCouponsResDto.setCouponCodeId( couponCode.getId() ); findUserCouponsResDto.setReceiveDate( couponCode.getReceiveDate() ); findUserCouponsResDto.setUsedDate( couponCode.getUsedDate() ); findUserCouponsResDto.setUsed( couponCode.isUsed() ); } if ( couponRo != null ) { if ( couponRo.getEnable() != null ) { findUserCouponsResDto.setEnable( couponRo.getEnable() ); } } findUserCouponsResDto.setExpireDate( CouponConvert.getMaxDate(couponCode.getUsageEndDate(), couponRo==null?null:couponRo.getUsageEndDate()) ); return findUserCouponsResDto; } }
一对多
@Mapping(target = "batchSoaGiveOutCouponItems",expression ="java(validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(validateSendCouponReqVo.getValidateSendCouponItemReqVos()))") public BatchSoaGiveOutCouponRequestVo validateSendCouponReqVoToBatchSoaGiveOutCouponRequestVo(ValidateSendCouponReqVo validateSendCouponReqVo); public List<BatchSoaGiveOutCouponRequestVo.BatchSoaGiveOutCouponItem> validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(List<ValidateSendCouponReqVo.ValidateSendCouponItemReqVo> validateSendCouponItemReqVos); @Mapping(target = "couponReceiveChannel",ignore = true)//忽略set public BatchSoaGiveOutCouponRequestVo.BatchSoaGiveOutCouponItem validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(ValidateSendCouponReqVo.ValidateSendCouponItemReqVo validateSendCouponItemReqVos);
转换
@Component public class CouponConvertImpl implements CouponConvert { @Override public BatchSoaGiveOutCouponRequestVo validateSendCouponReqVoToBatchSoaGiveOutCouponRequestVo(ValidateSendCouponReqVo validateSendCouponReqVo) { if ( validateSendCouponReqVo == null ) { return null; } BatchSoaGiveOutCouponRequestVo batchSoaGiveOutCouponRequestVo = new BatchSoaGiveOutCouponRequestVo(); batchSoaGiveOutCouponRequestVo.setBatchSoaGiveOutCouponItems( validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(validateSendCouponReqVo.getValidateSendCouponItemReqVos()) ); return batchSoaGiveOutCouponRequestVo; } @Override public List<BatchSoaGiveOutCouponItem> validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(List<ValidateSendCouponItemReqVo> validateSendCouponItemReqVos) { if ( validateSendCouponItemReqVos == null ) { return null; } List<BatchSoaGiveOutCouponItem> list = new ArrayList<BatchSoaGiveOutCouponItem>( validateSendCouponItemReqVos.size() ); for ( ValidateSendCouponItemReqVo validateSendCouponItemReqVo : validateSendCouponItemReqVos ) { list.add( validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem( validateSendCouponItemReqVo ) ); } return list; } @Override public BatchSoaGiveOutCouponItem validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(ValidateSendCouponItemReqVo validateSendCouponItemReqVos) { if ( validateSendCouponItemReqVos == null ) { return null; } BatchSoaGiveOutCouponItem batchSoaGiveOutCouponItem = new BatchSoaGiveOutCouponItem(); batchSoaGiveOutCouponItem.setUserId( validateSendCouponItemReqVos.getUserId() ); batchSoaGiveOutCouponItem.setUserMobile( validateSendCouponItemReqVos.getUserMobile() ); batchSoaGiveOutCouponItem.setCouponId( validateSendCouponItemReqVos.getCouponId() ); batchSoaGiveOutCouponItem.setMemberId( validateSendCouponItemReqVos.getMemberId() ); batchSoaGiveOutCouponItem.setQuantity( validateSendCouponItemReqVos.getQuantity() ); return batchSoaGiveOutCouponItem; } }
忽略属性
@Mapping(target = "couponReceiveChannel",ignore = true) public BatchSoaGiveOutCouponRequestVo.BatchSoaGiveOutCouponItem validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(ValidateSendCouponReqVo.ValidateSendCouponItemReqVo validateSendCouponItemReqVos);
转换后
@Override public BatchSoaGiveOutCouponItem validateSendCouponItemReqVoToBatchSoaGiveOutCouponItem(ValidateSendCouponItemReqVo validateSendCouponItemReqVos) { if ( validateSendCouponItemReqVos == null ) { return null; } BatchSoaGiveOutCouponItem batchSoaGiveOutCouponItem = new BatchSoaGiveOutCouponItem(); batchSoaGiveOutCouponItem.setUserId( validateSendCouponItemReqVos.getUserId() ); batchSoaGiveOutCouponItem.setUserMobile( validateSendCouponItemReqVos.getUserMobile() ); batchSoaGiveOutCouponItem.setCouponId( validateSendCouponItemReqVos.getCouponId() ); batchSoaGiveOutCouponItem.setMemberId( validateSendCouponItemReqVos.getMemberId() ); batchSoaGiveOutCouponItem.setQuantity( validateSendCouponItemReqVos.getQuantity() ); return batchSoaGiveOutCouponItem; }
一个对象set到另外一个对象
public MaotaiBookingPo setMaotaiBookingPo(@MappingTarget MaotaiBookingPo maotaiBookingPo, AppointmentReqDto appointmentReqDto);
自动生成后: @Override public MaotaiBookingPo setMaotaiBookingPo(MaotaiBookingPo maotaiBookingPo, AppointmentReqDto appointmentReqDto) { if ( appointmentReqDto == null ) { return null; } maotaiBookingPo.setId( appointmentReqDto.getId() ); maotaiBookingPo.setUserId( appointmentReqDto.getUserId() ); maotaiBookingPo.setMobile( appointmentReqDto.getMobile() ); maotaiBookingPo.setName( appointmentReqDto.getName() ); maotaiBookingPo.setIdCard( appointmentReqDto.getIdCard() ); maotaiBookingPo.setReceiveAddr( appointmentReqDto.getReceiveAddr() ); maotaiBookingPo.setLon( appointmentReqDto.getLon() ); maotaiBookingPo.setLat( appointmentReqDto.getLat() ); maotaiBookingPo.setProvinceId( appointmentReqDto.getProvinceId() ); maotaiBookingPo.setProvinceName( appointmentReqDto.getProvinceName() ); maotaiBookingPo.setCityId( appointmentReqDto.getCityId() ); maotaiBookingPo.setCityName( appointmentReqDto.getCityName() ); maotaiBookingPo.setDistrictId( appointmentReqDto.getDistrictId() ); maotaiBookingPo.setDistrictName( appointmentReqDto.getDistrictName() ); maotaiBookingPo.setActivityId( appointmentReqDto.getActivityId() ); return maotaiBookingPo; }
常见问题
与lombok冲突解决
clean install就可以看到对应的实现类
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>${java.version}</source> <target>${java.version}</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>${lombok.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
属性相同不自动生成映射
生成了Impl但是属性相同的没有自动生成set方法,手动添加get set方法不使用lombok就没有问题
个人解决方式:
1.尝试升级了lombok版本 我是从从1.14.8 提高到1.18.2就行了
2.保证没有依赖lombok冲突 比如当前项目引入了lombok 其他项目又引入了 版本不一致
或者是:mapstruct:1.3.0.Final,对应lombok:1.18.10 就可以正常使用了!
启动报错
java: Internal error in the mapping processor: java.lang.NullPointerException: Cannot invoke "java.net.URL.toExternalForm()" because "resource" is null at org.mapstruct.ap.internal.processor.DefaultVersionInformation.createManifestUrl(DefaultVersionInformation.java:182) at org.mapstruct.ap.internal.processor.DefaultVersionInformation.openManifest(DefaultVersionInformation.java:153) at org.mapstruct.ap.internal.processor.DefaultVersionInformation.getLibraryName(DefaultVersionInformation.java:129) at org.mapstruct.ap.internal.processor.DefaultVersionInformation.getCompiler(DefaultVersionInformation.java:122) at org.mapstruct.ap.internal.processor.DefaultVersionInformation.fromProcessingEnvironment(DefaultVersionInformation.java:95) at org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext.<init>(DefaultModelElementProcessorContext.java:50) at org.mapstruct.ap.MappingProcessor.processMapperElements(MappingProcessor.java:218) at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:156) at org.jetbrains.jps.javac.APIWrappers$ProcessorWrapper.process(APIWrappers.java:206) at jdk.internal.reflect.GeneratedMethodAccessor12.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.jetbrains.jps.javac.APIWrappers$1.invoke(APIWrappers.java:362) at jdk.proxy2/org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor.process(Unknown Source) at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:1023) at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:939) at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1267) at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1382) at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1234) at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:916) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94) at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:239) at org.jetbrains.jps.incremental.java.JavaBuilder.lambda$compileJava$2(JavaBuilder.java:519) at org.jetbrains.jps.incremental.java.JavaBuilder.invokeJavac(JavaBuilder.java:582) at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:517) at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:361) at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:286) at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:240) at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1556) at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:1185) at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:1336) at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:1150) at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:918) at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:474) at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:197) at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:150) at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:387) at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:212) at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler.lambda$channelRead0$0(BuildMain.java:211) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)
idea增加配置
-Djps.track.ap.dependencies=false
打包报错
maven install cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment
检查jdk版本
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!