mapstruct 如何跳过 checkstyle 的代码规范检测?

mapstruct 文档:
MapStruct 1.6.0 Reference Guide

背景

基于 spring-boot-starter-web 的普通web项目,使用了lombok插件、mapstruct插件辅助开发。
现要求代码开发规范要过 maven-checkstyle-plugin 插件的检测。
maven-checkstyle-plugin 的代码风格配置文件中要求 if 关键和后面的括号不能有空格,如:

if(po == null){
  return null;
}...

而正常的代码规范是有空格的,比如:


image.png

经过maven打包构建发现,checkstyle 插件指定在 package 阶段进行检测,如下:


image.png

执行 mvn clean package,报错如下:


image.png

mapstruct的原理

MapSturct 是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器(annotation processor)

简单的说下,想了解具体的自行百度。

在 compile 过程中:

  1. javac对源代码进行分析,生成了一棵抽象语法树(AST)
  2. 过程中调用了实现 “jsr 269 API”的 mapstruct,mapstruct在 target目录下生成了 generated-sources目录,为bean转换的java实现类,如图:


    image.png

    这里说一下编译时解析,有两种方式:

  • APT(Annotation Processing Tool) 已过时
  • API(Pluggable Annotation Processing API)
    mapstruct就是用了第二种方式 注解解析器
  1. 编译 .java -> .class

为什么lombok不受影响

lombok和mapstruct都是在编译时做手脚,但lombok和 cglib动态代理一样,用的那个字节码直接写入的技术,不会生成 java源文件,也就不受 checkstyle插件的影响。

原因

checkstyle 插件扫到了 target 目录下 mapstruct 用 freemarker 基于 ftl 模版生成的 impl 实现类,如图:


image.png

解决思路

  1. 弃用 mapstruct,或等mapstruct生成好之后把impl方法复制过来改改格式。。。
    当然可以,不过太累了,也不是个常规的办法。

  2. checkstyle插件目的是约束开发代码的规范,直接指定其检测的目录不行吗?
    当然可以,不过我这里插件配置是甲方规定的,到时候这块是在自动化构建ci/cd过程中人家配置的,人家指定的规则可不配合你改,人家就想都检测。
    一般人也不会去检测,就算自己想检测规范大不了配置个范围,比如:
    配置代码检测的范围:

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>3.1.2</version>
                <configuration>
                    <configLocation>style/checkstyle.xml</configLocation>
                    <failsOnError>false</failsOnError>
                    <!-- 配置代码检测的范围 -->
<!--                    <sourceDirectories>-->
<!--                        <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>-->
<!--                        <sourceDirectory>${project.build.testSourceDirectory}</sourceDirectory>-->
<!--                    </sourceDirectories>-->
                </configuration>
                <executions>
                    <execution>
                        <id>checkstyle-check</id>
                        <phase>package</phase>
<!--                        <phase>compile</phase>-->
                        <goals>
                            <goal>check</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
  1. 覆盖 mapstruct 的模版,指定使用自己的 ftl 模版
    行不通,因为他是“编译时解析”无法正常覆盖!而且,查看了mapstruct的官方文档和源代码,没有暴露任何修改ftl的spi。

  2. 既然覆盖不了,fork一份源码自己改不行吗?
    当然可以,不过暂时没去这么做。

  3. 仔细看maven构建的生命过程,mapstruct是发生在compile这步,而 checkstyle是发生在package这步之前,如图:


    image.png

    那我们在 target 目录下 generated-sources 文件夹等 compile 结束后 class文件都生成好之后,把这个临时的java文件夹给删了不就好了?可以,配置如下:

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <delete dir="${project.build.directory}/generated-sources" />
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

【建议放在checkstyle插件前,这样即便是checkstyle指定检测环节为compile也不影响。checkstyle如果指定检测环节在compile之前那就更不影响了因为那时候mapstruct还没上岗工作】

上面加的删除generated-sources步骤,在构建中,如图:


image.png

mapstruct能否配置删了自己渲染的 java文件夹?
不能,因为他只负责生产java源文件即 generated-sources目录下的文件,后面的“编译到class”这一步他已经“歇班”了。
测试:


image.png

最后

如果你能改checkstyle的扫描范围当然是最合理的了。
如果不考虑那点儿性能,用BeanUtils反射也挺好。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容