温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Mapstruct对象插入数据库某个字段总是为空怎么解决

发布时间:2022-07-28 10:29:07 来源:亿速云 阅读:147 作者:iii 栏目:开发技术

本篇内容主要讲解“Mapstruct对象插入数据库某个字段总是为空怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Mapstruct对象插入数据库某个字段总是为空怎么解决”吧!

前言

在一次需求的开发过程中,发现一个对象插入数据库时某个字段总是为空。

版本:lombok:1.18.24、mapstruct:1.5.2.Final

简化后的代码如下:

@Autowired     private PersonService personService;     public void test1(){         Person person = personService.findById(1L);         PersonDto personDto = PersonMapper.INSTANCE.personToPersonDto(person);         personService.insert(personDto);     }

这么简单的逻辑按理说不会出幺蛾子啊,我先排查了数据库里person id=1的记录发现值是有的啊,然后又排查了我的insert方法,也是没问题的。

经过一段时间的排查,才发现是

PersonDto personDto = PersonMapper.INSTANCE.personToPersonDto(person);

这行代码的问题。证据截图如下:

Mapstruct对象插入数据库某个字段总是为空怎么解决

前面的时候addTeacherNum还有值,转化后怎么又没值了呢?

大家看到这里肯定猜测是不是我属性名不对,或者属性类型不对。我甚至还删除了之后用复制的方式来保证没有手敲敲错的情况。

Mapstruct对象插入数据库某个字段总是为空怎么解决

完全是一模一样的属性啊。

我们知道mapstruct是编译时通过我们的PersonMapper接口来实现实现类,实现类里是setter、getter方法来实现的。于是我打开了PersonMapper的实现类准备一探究竟:

public class PersonMapperImpl implements PersonMapper {     public PersonMapperImpl() {     }     public PersonDto personToPersonDto(Person person) {         if (person == null) {             return null;         } else {             PersonDtoBuilder personDto = PersonDto.builder();             personDto.name(person.getName());             return personDto.build();         }     } }

竟然没有对我这个属性addTeacherNum进行赋值。这让我百思不得其解。只能去看看源码,试图找出原因。

如何调试Maven插件

前面我们提到mapstruct是在代码编译的时候就开始生成代码了,于是我们需要对maven编译期进行调试。方法如下:

  • maven debug命令

mvnDebug clean compile
  • idea远程debug

Mapstruct对象插入数据库某个字段总是为空怎么解决

新建一个remote,然后修改端口为8000,然后在执行maven命令的同时,启动这个remote即可。

源码解析

断点应该打在哪里呢?

我们查看mapstruct的结构,一般先从配置的文件入手

Mapstruct对象插入数据库某个字段总是为空怎么解决

找到了这个MappingProcessor类,我们可以看到这里面有个process方法,里面又调用了如下的这个方法:

private void processMapperTypeElement(ProcessorContext context, TypeElement mapperTypeElement) {     Object model = null;     for ( ModelElementProcessor<?, ?> processor : getProcessors() ) {         try {             model = process( context, processor, mapperTypeElement, model );         }         catch ( AnnotationProcessingException e ) {            //省略         }     } }

这段代码其实就是调用getProcessors()方法拿到多个processor,然后遍历调用。而这个getProcessors()就是从配置文件里通过SPI的方式加载对象。

Mapstruct对象插入数据库某个字段总是为空怎么解决

这里面我们重点关注这个Processor:MapperCreationProcessor。它的process方法如下:

@Override public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<SourceMethod> sourceModel) {     this.elementUtils = context.getElementUtils();     this.typeUtils = context.getTypeUtils();     this.messager =         new MapperAnnotatedFormattingMessenger( context.getMessager(), mapperTypeElement, context.getTypeUtils() );     this.options = context.getOptions();     this.versionInformation = context.getVersionInformation();     this.typeFactory = context.getTypeFactory();     this.accessorNaming = context.getAccessorNaming();     MapperOptions mapperOptions = MapperOptions.getInstanceOn( mapperTypeElement, context.getOptions() );     List<MapperReference> mapperReferences = initReferencedMappers( mapperTypeElement, mapperOptions );     MappingBuilderContext ctx = new MappingBuilderContext(         typeFactory,         elementUtils,         typeUtils,         messager,         accessorNaming,         context.getEnumMappingStrategy(),         context.getEnumTransformationStrategies(),         options,         new MappingResolverImpl(             messager,             elementUtils,             typeUtils,             typeFactory,             new ArrayList<>( sourceModel ),             mapperReferences,             options.isVerbose()         ),         mapperTypeElement,         //sourceModel is passed only to fetch the after/before mapping methods in lifecycleCallbackFactory;         //Consider removing those methods directly into MappingBuilderContext.         Collections.unmodifiableList( sourceModel ),         mapperReferences     );     this.mappingContext = ctx;     return getMapper( mapperTypeElement, mapperOptions, sourceModel ); }

getMapper里面有一段这个方法引起我的注意:

List<MappingMethod> mappingMethods = getMappingMethods( mapperOptions, methods );

猜测这段就是获取要写入的set、get方法。 于是一路跟踪:

发现mapstruct里面把方法分为了下面四类,而我的addTeacherNum属性通过lombok生成的方法methodType被分到了ADDER里面。

Mapstruct对象插入数据库某个字段总是为空怎么解决

而在生成我的Mapper实现类的时候它会只过滤setter方法。

List<Accessor> candidates = new ArrayList<>( getSetters() );

到此,相信大家对“Mapstruct对象插入数据库某个字段总是为空怎么解决”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI