文章目录
- Checkstyle
- 主要特点
- 使用场景
- 配置与使用
- checkstyle.xml
- suppressions.xml
- 验证
- 打包时验证
- 执行命令验证
- Spotless
- 配置文件内容
- Java配置部分
- POM 配置部分
- Markdown 配置部分
- Up to Date Checking
- 执行部分
- 验证
- 打包时验证
- 在插件中执行命令验证
- Checkstyle + Spotless 结合
- checkstyle.xml
- suppressions.xml
- pom.xml
Checkstyle
Checkstyle 是一个开源的代码质量管理工具,主要用于帮助程序员遵守编程标准和代码规范。它通过自动化检查Java源代码,识别出不符合预定义或自定义编码规则的部分,从而提升代码的可读性、一致性和维护性。Checkstyle 支持广泛的检查规则,包括但不限于命名约定、类设计、 Imports组织、空白使用、代码格式化等。
主要特点
-
丰富的规则集:Checkstyle 提供了一套全面的内置规则,涵盖了从文件命名、缩进、行长度、注释风格到复杂度测量等多方面的检查。用户可以根据需要启用或禁用这些规则。
-
高度可配置性:除了使用默认规则外,用户还可以创建自定义规则集,调整现有规则的属性,或者完全编写自己的检查规则,以适应特定项目或团队的编码标准。
-
集成简便:Checkstyle 可以轻松地集成到多种开发环境和构建流程中,比如Eclipse、IntelliJ IDEA、Maven、Gradle等。这样可以在代码提交前、编译时或持续集成过程中自动执行检查。
-
即时反馈:集成到IDE时,Checkstyle 能够实时提供反馈,开发者在编码过程中就能看到不合规的代码提示,及时修正。
-
报告生成:Checkstyle 可以生成详细的报告,指出哪些文件、哪些行存在违规情况,甚至可以集成到持续集成服务器上,为团队提供统一的代码质量视图。
使用场景
- 团队协作:确保整个团队遵循统一的编码规范,减少代码审查中的样式争议。
- 项目维护:对于长期维护的项目,保持代码风格的一致性,提高代码的可读性和可维护性。
- 新开发者培训:帮助新加入的开发者快速了解并遵循项目的编码规范。
- 自动化代码质量控制:在持续集成和部署流程中,作为代码质量检查的一环,自动化拒绝不符合规范的代码提交。
配置与使用
Checkstyle 的配置文件通常是一个XML文件,定义了启用的检查规则及其参数。
在项目的pom.xml
中中配置依赖
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-checkstyle-plugin</artifactId><version>3.3.0</version><configuration><configLocation>./script/checkstyle/checkstyle.xml</configLocation><suppressionsLocation>./script/checkstyle/suppressions.xml</suppressionsLocation><includeTestSourceDirectory>true</includeTestSourceDirectory><consoleOutput>true</consoleOutput><failsOnError>true</failsOnError><linkXRef>false</linkXRef></configuration><executions><execution><id>validate</id><phase>validate</phase><goals><goal>check</goal></goals></execution></executions></plugin></plugins></build>
上文指定了两个风格配置文件,可以根据自己需求去自定义。
checkstyle.xml
<?xml version="1.0"?>
<!--~ Licensed to the Apache Software Foundation (ASF) under one or more~ contributor license agreements. See the NOTICE file distributed with~ this work for additional information regarding copyright ownership.~ The ASF licenses this file to You under the Apache License, Version 2.0~ (the "License"); you may not use this file except in compliance with~ the License. You may obtain a copy of the License at~~ http://www.apache.org/licenses/LICENSE-2.0~~ Unless required by applicable law or agreed to in writing, software~ distributed under the License is distributed on an "AS IS" BASIS,~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.~ See the License for the specific language governing permissions and~ limitations under the License.--><!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd"><module name="Checker"><module name="SuppressWarningsFilter"/><property name="charset" value="UTF-8"/><property name="severity" value="error"/><property name="fileExtensions" value="java, properties, xml"/><!-- Excludes all 'module-info.java' files --><!-- See https://checkstyle.org/config_filefilters.html --><module name="BeforeExecutionExclusionFileFilter"><property name="fileNamePattern" value="module\-info\.java$"/></module><module name="SuppressionFilter"><property name="file" value="${org.checkstyle.google.suppressionfilter.config}"default="checkstyle-suppressions.xml"/><property name="optional" value="true"/></module><module name="LineLength"><property name="fileExtensions" value="java"/><property name="max" value="200"/><property name="ignorePattern"value="^package.*|^import.*|a href|href|http://|https://|ftp://"/></module><module name="TreeWalker"><module name="OuterTypeFilename"/><module name="IllegalTokenText"><property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/><property name="format"value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/><property name="message"value="Consider using special escape sequence instead of octal value or Unicode escaped value."/></module><module name="AvoidEscapedUnicodeCharacters"><property name="allowEscapesForControlCharacters" value="true"/><property name="allowByTailComment" value="true"/><property name="allowNonPrintableEscapes" value="true"/></module><module name="OneTopLevelClass"/><module name="NoLineWrap"><property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/></module><module name="EmptyBlock"><property name="option" value="TEXT"/><property name="tokens"value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/></module><module name="SuppressionXpathSingleFilter"><property name="id" value="RightCurlyAlone"/><property name="query" value="//RCURLY[parent::SLIST[count(./*)=1]or preceding-sibling::*[last()][self::LCURLY]]"/></module><module name="WhitespaceAfter"><property name="tokens"value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE,LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, DO_WHILE"/></module><module name="OneStatementPerLine"/><module name="MultipleVariableDeclarations"/><module name="ArrayTypeStyle"/><module name="MissingSwitchDefault"/><module name="FallThrough"/><module name="UpperEll"/><module name="UnusedImports"/><module name="EmptyLineSeparator"><property name="tokens"value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,COMPACT_CTOR_DEF"/><property name="allowNoEmptyLineBetweenFields" value="true"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapDot"/><property name="tokens" value="DOT"/><property name="option" value="nl"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapEllipsis"/><property name="tokens" value="ELLIPSIS"/><property name="option" value="EOL"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapArrayDeclarator"/><property name="tokens" value="ARRAY_DECLARATOR"/><property name="option" value="EOL"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapMethodRef"/><property name="tokens" value="METHOD_REF"/><property name="option" value="nl"/></module><module name="PackageName"><property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/><message key="name.invalidPattern"value="Package name ''{0}'' must match pattern ''{1}''."/></module><module name="TypeName"><property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,ANNOTATION_DEF, RECORD_DEF"/><message key="name.invalidPattern"value="Type name ''{0}'' must match pattern ''{1}''."/></module><module name="MemberName"><property name="format" value="^[a-z][a-z0-9]?[a-zA-Z0-9]*$"/><message key="name.invalidPattern"value="Member name ''{0}'' must match pattern ''{1}''."/></module><module name="ParameterName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Parameter name ''{0}'' must match pattern ''{1}''."/></module><module name="LambdaParameterName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/></module><module name="CatchParameterName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Catch parameter name ''{0}'' must match pattern ''{1}''."/></module><module name="LocalVariableName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Local variable name ''{0}'' must match pattern ''{1}''."/></module><module name="PatternVariableName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Pattern variable name ''{0}'' must match pattern ''{1}''."/></module><module name="ClassTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Class type name ''{0}'' must match pattern ''{1}''."/></module><module name="RecordComponentName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$" /><message key="name.invalidPattern" value="Record component name ''{0}'' must match pattern ''{1}''." /></module><module name="RecordTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Record type name ''{0}'' must match pattern ''{1}''."/></module><module name="RecordTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Record type name ''{0}'' must match pattern ''{1}''."/></module><module name="MethodTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Method type name ''{0}'' must match pattern ''{1}''."/></module><module name="InterfaceTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Interface type name ''{0}'' must match pattern ''{1}''."/></module><module name="Indentation"><property name="basicOffset" value="4"/><property name="braceAdjustment" value="0"/><property name="caseIndent" value="4"/><property name="throwsIndent" value="2"/><property name="lineWrappingIndentation" value="4"/><property name="arrayInitIndent" value="8"/></module><module name="AbbreviationAsWordInName"><property name="ignoreFinal" value="false"/><property name="allowedAbbreviationLength" value="0"/><property name="allowedAbbreviations"value="XML, URL, ID, FTP, DTO, VO, DO, TO, PO, BO, POJO, HTTP, IP, IE"/><property name="tokens"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,RECORD_COMPONENT_DEF"/></module><module name="NoWhitespaceBefore"><property name="tokens"value="COMMA, SEMI, POST_INC, POST_DEC, DOT,LABELED_STAT, METHOD_REF"/><property name="allowLineBreaks" value="true"/></module><module name="ParenPad"><property name="tokens"value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,RECORD_DEF"/></module><module name="AnnotationLocation"><property name="id" value="AnnotationLocationMostCases"/><property name="tokens"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,RECORD_DEF, COMPACT_CTOR_DEF"/></module><module name="AnnotationLocation"><property name="id" value="AnnotationLocationVariables"/><property name="tokens" value="VARIABLE_DEF"/><property name="allowSamelineMultipleAnnotations" value="true"/></module><module name="NonEmptyAtclauseDescription"/><module name="InvalidJavadocPosition"/><module name="JavadocTagContinuationIndentation"><property name="offset" value="0"/></module><module name="AtclauseOrder"><property name="tagOrder" value="@param, @return, @throws, @deprecated"/><property name="target"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/></module><module name="JavadocMethod"><property name="accessModifiers" value="public"/><property name="allowMissingParamTags" value="true"/><property name="allowMissingReturnTag" value="true"/><property name="allowedAnnotations" value="Override, Test"/><property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/></module><module name="MissingJavadocType"><property name="scope" value="protected"/><property name="tokens"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,RECORD_DEF, ANNOTATION_DEF"/><property name="excludeScope" value="nothing"/></module><module name="MethodName"><property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/><message key="name.invalidPattern"value="Method name ''{0}'' must match pattern ''{1}''."/></module><module name="SingleLineJavadoc"><property name="ignoreInlineTags" value="false"/></module><module name="EmptyCatchBlock"><property name="exceptionVariableName" value="ignore"/></module><module name="CommentsIndentation"><property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/></module><module name="SuppressionXpathFilter"><property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"default="checkstyle-xpath-suppressions.xml"/><property name="optional" value="true"/></module><module name="SuppressWarningsHolder"/><module name="SuppressionCommentFilter"><property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/><property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/><property name="checkFormat" value="$1"/></module><module name="SuppressWithNearbyCommentFilter"><property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/><property name="checkFormat" value="$1"/><property name="influenceFormat" value="1"/></module><module name="RegexpSinglelineJava"><property name="format" value="^.*(@author|@date).*" /><property name="message" value="Java file header cannot contain @author or @date" /></module><!--IMPORT CHECKS--><module name="RedundantImport"><!-- Checks for redundant import statements. --><property name="severity" value="error"/><message key="import.redundancy"value="Redundant import {0}."/></module><module name="ImportOrder"><property name="severity" value="error"/><!-- This ensures that static imports go first. --><property name="option" value="top"/><property name="sortStaticImportsAlphabetically" value="true"/><property name="tokens" value="STATIC_IMPORT, IMPORT"/><message key="import.ordering"value="Import {0} appears after other imports that it should precede"/></module><module name="AvoidStarImport"><property name="severity" value="error"/></module><module name="RedundantModifier"><!-- Checks for redundant modifiers on various symbol definitions.See: http://checkstyle.sourceforge.net/config_modifier.html#RedundantModifier--><property name="tokens" value="METHOD_DEF, VARIABLE_DEF, ANNOTATION_FIELD_DEF, INTERFACE_DEF, CLASS_DEF, ENUM_DEF"/></module><module name="UnusedImports"><property name="severity" value="error"/><property name="processJavadoc" value="true"/><message key="import.unused"value="Unused import: {0}."/></module><!--WHITESPACE CHECKS--><module name="WhitespaceAround"><!-- Checks that various tokens are surrounded by whitespace.This includes most binary operators and keywords followedby regular or curly braces.--><property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/><property name="severity" value="error"/></module><module name="WhitespaceAfter"><!-- Checks that commas, semicolons and typecasts are followed bywhitespace.--><property name="tokens" value="COMMA, SEMI, TYPECAST"/></module><module name="NoWhitespaceAfter"><!-- Checks that there is no whitespace after various unary operators.Linebreaks are allowed.--><property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,UNARY_PLUS"/><property name="allowLineBreaks" value="true"/><property name="severity" value="error"/></module><module name="NoWhitespaceBefore"><!-- Checks that there is no whitespace before various unary operators.Linebreaks are allowed.--><property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/><property name="allowLineBreaks" value="true"/><property name="severity" value="error"/></module><module name="OperatorWrap"><!-- Checks that operators like + and ? appear at newlines rather thanat the end of the previous line.--><property name="option" value="NL"/><property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL,GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD,NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/></module><module name="OperatorWrap"><!-- Checks that assignment operators are at the end of the line. --><property name="option" value="eol"/><property name="tokens" value="ASSIGN"/></module><module name="ParenPad"><!-- Checks that there is no whitespace before close parens or afteropen parens.--><property name="severity" value="error"/></module><module name="ModifierOrder"/></module>
</module>
suppressions.xml
<?xml version="1.0"?>
<!--Licensed to the Apache Software Foundation (ASF) under oneor more contributor license agreements. See the NOTICE filedistributed with this work for additional informationregarding copyright ownership. The ASF licenses this fileto you under the Apache License, Version 2.0 (the"License"); you may not use this file except in compliancewith the License. You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing,software distributed under the License is distributed on an"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANYKIND, either express or implied. See the License for thespecific language governing permissions and limitationsunder the License.-->
<!DOCTYPE suppressions PUBLIC"-//Puppy Crawl//DTD Suppressions 1.1//EN""http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"><suppressions><suppress checks="JavadocPackage" files=".*[\\/]src[\\/]test[\\/].*"/><suppress checks="JavadocPackage" files=".*[\\/]maven-archetypes[\\/].*"/><suppress checks="JavadocPackage" files=".*[\\/]examples[\\/].*"/><!-- suppress javadoc check for impl classes and package-info.java --><suppress checks="JavadocType" files=".*Impl\.java$" /><suppress checks="JavadocStyle" files=".+[\\/]package-info\.java$" /><!-- suppress all checks in the generated directories --><suppress checks=".*" files=".+[\\/]generated[\\/].+\.java"/><suppress checks=".*" files=".+[\\/]generated-sources[\\/].+\.java"/><suppress checks=".*" files=".+[\\/]generated-test-sources[\\/].+\.java"/><!-- suppress most all checks expect below--><suppress checks="^(?!.*(UnusedImports|IllegalImport)).*$" files=".*[\\/]src[\\/]test[\\/].*"/>
</suppressions>
tips: 在项目最外层pom.xml中引入依赖就可以,子项目可以自动继承该配置
验证
打包时验证
mvn package
时,会自动运行检查,如果有不符合风格的会提示打包异常。此时需要手动去修改,checkstyle插件不具备自动修复能力。
如:
[INFO] 开始检查……
[ERROR] /Users/mac/IdeaProjects/all-in-one/redis/xxx:12:1: Import java.util.List appears after other imports that it should precede [ImportOrder]
执行命令验证
这四个命令都涉及到 Checkstyle 工具的不同功能和用途:
checkstyle:check
- 这个命令用于执行 Checkstyle 插件的
check
目标。执行此命令时,Checkstyle 插件将会检查你的代码是否符合预定义的代码规范(规则)。如果代码中存在不符合规范的地方,会输出相应的警告或错误信息。
- 这个命令用于执行 Checkstyle 插件的
checkstyle:checkstyle
- 这个命令用于生成 Checkstyle 报告。执行此命令后,Checkstyle 插件会分析代码,并生成一个详细的报告,展示代码中哪些地方违反了规范,以及如何修正这些问题。
checkstyle:checkstyle-aggregate
- 这个命令与上一个命令类似,也是生成 Checkstyle 报告,但它会在聚合项目(多个子项目组成的项目)的上下文中运行。这意味着它会汇总所有子项目的检查结果,并生成一个总体的报告。
checkstyle:help
- 这个命令用于查看 Checkstyle 插件的帮助文档。执行此命令后,会列出 Checkstyle 插件支持的所有命令和参数选项,帮助你理解如何使用 Checkstyle 插件及其配置选项。
Spotless
配置文件内容
<plugin><groupId>com.diffplug.spotless</groupId><artifactId>spotless-maven-plugin</artifactId><version>2.29.0</version><configuration><skip>false</skip><java><excludes><exclude>src/main/java/wiki/hadoop/test/*.*</exclude></excludes><googleJavaFormat><version>1.7</version><style>AOSP</style></googleJavaFormat><removeUnusedImports /><formatAnnotations /><importOrder><order>wiki.hadoop,org.apache,org,,javax,java,\#</order></importOrder><replaceRegex><name>Remove wildcard imports</name><searchRegex>import\s+(static)*\s*[^\*\s]+\*;(\r\n|\r|\n)</searchRegex><replacement>$1</replacement></replaceRegex><replaceRegex><name>Block hutool</name><searchRegex>import\s+cn\.hutool\.[^\*\s]*(|\*);(\r\n|\r|\n)</searchRegex><replacement>$1</replacement></replaceRegex></java><pom><sortPom><encoding>UTF-8</encoding><nrOfIndentSpace>4</nrOfIndentSpace><keepBlankLines>true</keepBlankLines><indentBlankLines>false</indentBlankLines><indentSchemaLocation>true</indentSchemaLocation><spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement><sortModules>false</sortModules><sortExecutions>false</sortExecutions><predefinedSortOrder>custom_1</predefinedSortOrder><expandEmptyElements>false</expandEmptyElements><sortProperties>false</sortProperties></sortPom><replace><name>Leading blank line</name><search>project</search><replacement>project</replacement></replace></pom><markdown><includes><include>docs/**/*.md</include></includes><excludes><exclude>**/.github/**/*.md</exclude></excludes><flexmark /></markdown><upToDateChecking><enabled>true</enabled></upToDateChecking></configuration><executions><execution><id>spotless-check</id><goals><goal>check</goal></goals><phase>validate</phase></execution></executions></plugin>
Java配置部分
-
skip
: 是否跳过Spotless插件的执行,这里设置为false
表示不跳过。 -
excludes
: 排除特定文件或目录,这里排除了src/main/java/wiki/hadoop/test
目录下的所有文件。 -
googleJavaFormat
: 使用 Google Java 格式化工具,版本为1.7
,样式为AOSP
。 -
removeUnusedImports
: 移除未使用的import语句。 -
formatAnnotations
: 格式化注解。 -
importOrder
: 定义import语句的顺序,确保不同来源的import语句有固定的顺序,便于维护和阅读。<importOrder><order>wiki.hadoop,org.apache,org,,javax,java,\#</order> </importOrder>
- 定义了import语句的排序规则,顺序为:
- wiki.hadoop
- org.apache
- org
- 空 (所有未配置的包)
- javax
- java
- # (标识所有静态导入)
- 定义了import语句的排序规则,顺序为:
-
replaceRegex
: 使用正则表达式替换特定内容:Remove wildcard imports
: 移除使用通配符的import。Block powermock
: 阻止使用 powermock 库。(禁止使用哪些包)
POM 配置部分
-
sortPom
: POM文件排序配置,包括编码、缩进等细节:encoding
: 文件编码,设置为UTF-8
。nrOfIndentSpace
: 缩进空格数,设置为4
。keepBlankLines
: 是否保留空行,设置为true
。indentBlankLines
: 是否缩进空行,设置为false
。indentSchemaLocation
: 是否缩进 schema 位置,设置为true
。spaceBeforeCloseEmptyElement
: 是否在空元素闭合前留空格,设置为true
。sortModules
: 是否排序模块,设置为false
。sortExecutions
: 是否排序执行,设置为false
。predefinedSortOrder
: 预定义排序顺序,设置为custom_1
。expandEmptyElements
: 是否展开空元素,设置为false
。sortProperties
: 是否排序属性,设置为false
。
-
replace
: 替换特定的内容,确保项目标记没有前导空白行。
Markdown 配置部分
includes
和excludes
: 指定包含和排除的Markdown文件。flexmark
: 使用Flexmark格式化Markdown文件。
Up to Date Checking
enabled
: 是否启用最新检查,这里设置为true
。
执行部分
<executions><execution><id>spotless-check</id><goals><goal>check</goal></goals><phase>validate</phase></execution>
</executions>
定义了一个执行阶段 validate
,在这个阶段执行 spotless:check
目标来检查代码格式。
验证
打包时验证
默认打包时会自动验证
在插件中执行命令验证
执行 mvn spotless:apply
自动修改代码
执行 mvn spotless:check
检查代码
Checkstyle + Spotless 结合
checkstyle.xml
在项目根目录创建文件script/checkstyle/checkstyle.xml
<?xml version="1.0"?>
<!--~ Licensed to the Apache Software Foundation (ASF) under one or more~ contributor license agreements. See the NOTICE file distributed with~ this work for additional information regarding copyright ownership.~ The ASF licenses this file to You under the Apache License, Version 2.0~ (the "License"); you may not use this file except in compliance with~ the License. You may obtain a copy of the License at~~ http://www.apache.org/licenses/LICENSE-2.0~~ Unless required by applicable law or agreed to in writing, software~ distributed under the License is distributed on an "AS IS" BASIS,~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.~ See the License for the specific language governing permissions and~ limitations under the License.--><!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd"><module name="Checker"><module name="SuppressWarningsFilter"/><property name="charset" value="UTF-8"/><property name="severity" value="error"/><property name="fileExtensions" value="java, properties, xml"/><!-- Excludes all 'module-info.java' files --><!-- See https://checkstyle.org/config_filefilters.html --><module name="BeforeExecutionExclusionFileFilter"><property name="fileNamePattern" value="module\-info\.java$"/></module><module name="SuppressionFilter"><property name="file" value="${org.checkstyle.google.suppressionfilter.config}"default="checkstyle-suppressions.xml"/><property name="optional" value="true"/></module><module name="LineLength"><property name="fileExtensions" value="java"/><property name="max" value="500"/><property name="ignorePattern"value="^package.*|^import.*|a href|href|http://|https://|ftp://"/></module><module name="TreeWalker"><module name="OuterTypeFilename"/><module name="IllegalTokenText"><property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/><property name="format"value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/><property name="message"value="Consider using special escape sequence instead of octal value or Unicode escaped value."/></module><module name="AvoidEscapedUnicodeCharacters"><property name="allowEscapesForControlCharacters" value="true"/><property name="allowByTailComment" value="true"/><property name="allowNonPrintableEscapes" value="true"/></module><module name="OneTopLevelClass"/><module name="NoLineWrap"><property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/></module><module name="EmptyBlock"><property name="option" value="TEXT"/><property name="tokens"value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/></module><module name="SuppressionXpathSingleFilter"><property name="id" value="RightCurlyAlone"/><property name="query" value="//RCURLY[parent::SLIST[count(./*)=1]or preceding-sibling::*[last()][self::LCURLY]]"/></module><module name="WhitespaceAfter"><property name="tokens"value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE,LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, DO_WHILE"/></module><module name="OneStatementPerLine"/><module name="MultipleVariableDeclarations"/><module name="ArrayTypeStyle"/><module name="MissingSwitchDefault"/><module name="FallThrough"/><module name="UpperEll"/><module name="UnusedImports"/><module name="EmptyLineSeparator"><property name="tokens"value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,COMPACT_CTOR_DEF"/><property name="allowNoEmptyLineBetweenFields" value="true"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapDot"/><property name="tokens" value="DOT"/><property name="option" value="nl"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapEllipsis"/><property name="tokens" value="ELLIPSIS"/><property name="option" value="EOL"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapArrayDeclarator"/><property name="tokens" value="ARRAY_DECLARATOR"/><property name="option" value="EOL"/></module><module name="SeparatorWrap"><property name="id" value="SeparatorWrapMethodRef"/><property name="tokens" value="METHOD_REF"/><property name="option" value="nl"/></module><module name="PackageName"><property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/><message key="name.invalidPattern"value="Package name ''{0}'' must match pattern ''{1}''."/></module><module name="TypeName"><property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,ANNOTATION_DEF, RECORD_DEF"/><message key="name.invalidPattern"value="Type name ''{0}'' must match pattern ''{1}''."/></module><module name="MemberName"><property name="format" value="^[a-z][a-z0-9]?[a-zA-Z0-9]*$"/><message key="name.invalidPattern"value="Member name ''{0}'' must match pattern ''{1}''."/></module><module name="ParameterName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Parameter name ''{0}'' must match pattern ''{1}''."/></module><module name="LambdaParameterName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/></module><module name="CatchParameterName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Catch parameter name ''{0}'' must match pattern ''{1}''."/></module><module name="LocalVariableName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Local variable name ''{0}'' must match pattern ''{1}''."/></module><module name="PatternVariableName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/><message key="name.invalidPattern"value="Pattern variable name ''{0}'' must match pattern ''{1}''."/></module><module name="ClassTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Class type name ''{0}'' must match pattern ''{1}''."/></module><module name="RecordComponentName"><property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$" /><message key="name.invalidPattern" value="Record component name ''{0}'' must match pattern ''{1}''." /></module><module name="RecordTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Record type name ''{0}'' must match pattern ''{1}''."/></module><module name="RecordTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Record type name ''{0}'' must match pattern ''{1}''."/></module><module name="MethodTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Method type name ''{0}'' must match pattern ''{1}''."/></module><module name="InterfaceTypeParameterName"><property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/><message key="name.invalidPattern"value="Interface type name ''{0}'' must match pattern ''{1}''."/></module><module name="Indentation"><property name="basicOffset" value="4"/><property name="braceAdjustment" value="0"/><property name="caseIndent" value="4"/><property name="throwsIndent" value="2"/><property name="lineWrappingIndentation" value="4"/><property name="arrayInitIndent" value="8"/></module><module name="AbbreviationAsWordInName"><property name="ignoreFinal" value="false"/><property name="allowedAbbreviationLength" value="0"/><property name="allowedAbbreviations"value="XML, URL, ID, FTP, DTO, VO, DO, TO, PO, BO, POJO, HTTP, IP, IE"/><property name="tokens"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,RECORD_COMPONENT_DEF"/></module><module name="NoWhitespaceBefore"><property name="tokens"value="COMMA, SEMI, POST_INC, POST_DEC, DOT,LABELED_STAT, METHOD_REF"/><property name="allowLineBreaks" value="true"/></module><module name="ParenPad"><property name="tokens"value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,RECORD_DEF"/></module><module name="AnnotationLocation"><property name="id" value="AnnotationLocationMostCases"/><property name="tokens"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,RECORD_DEF, COMPACT_CTOR_DEF"/></module><module name="AnnotationLocation"><property name="id" value="AnnotationLocationVariables"/><property name="tokens" value="VARIABLE_DEF"/><property name="allowSamelineMultipleAnnotations" value="true"/></module><module name="NonEmptyAtclauseDescription"/><module name="InvalidJavadocPosition"/><module name="JavadocTagContinuationIndentation"><property name="offset" value="0"/></module><module name="AtclauseOrder"><property name="tagOrder" value="@param, @return, @throws, @deprecated"/><property name="target"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/></module><module name="JavadocMethod"><property name="accessModifiers" value="public"/><property name="allowMissingParamTags" value="true"/><property name="allowMissingReturnTag" value="true"/><property name="allowedAnnotations" value="Override, Test"/><property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/></module><module name="MissingJavadocType"><property name="scope" value="protected"/><property name="tokens"value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,RECORD_DEF, ANNOTATION_DEF"/><property name="excludeScope" value="nothing"/></module><module name="MethodName"><property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/><message key="name.invalidPattern"value="Method name ''{0}'' must match pattern ''{1}''."/></module><module name="EmptyCatchBlock"><property name="exceptionVariableName" value="ignore"/></module><module name="CommentsIndentation"><property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/></module><module name="SuppressionXpathFilter"><property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"default="checkstyle-xpath-suppressions.xml"/><property name="optional" value="true"/></module><module name="SuppressWarningsHolder"/><module name="SuppressionCommentFilter"><property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/><property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/><property name="checkFormat" value="$1"/></module><module name="SuppressWithNearbyCommentFilter"><property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/><property name="checkFormat" value="$1"/><property name="influenceFormat" value="1"/></module><!--IMPORT CHECKS--><module name="RedundantImport"><!-- Checks for redundant import statements. --><property name="severity" value="error"/><message key="import.redundancy"value="Redundant import {0}."/></module><module name="AvoidStarImport"><property name="severity" value="error"/></module><module name="RedundantModifier"><!-- Checks for redundant modifiers on various symbol definitions.See: http://checkstyle.sourceforge.net/config_modifier.html#RedundantModifier--><property name="tokens" value="METHOD_DEF, VARIABLE_DEF, ANNOTATION_FIELD_DEF, INTERFACE_DEF, CLASS_DEF, ENUM_DEF"/></module><module name="UnusedImports"><property name="severity" value="error"/><property name="processJavadoc" value="true"/><message key="import.unused"value="Unused import: {0}."/></module><!--WHITESPACE CHECKS--><module name="WhitespaceAround"><!-- Checks that various tokens are surrounded by whitespace.This includes most binary operators and keywords followedby regular or curly braces.--><property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/><property name="severity" value="error"/></module><module name="WhitespaceAfter"><!-- Checks that commas, semicolons and typecasts are followed bywhitespace.--><property name="tokens" value="COMMA, SEMI, TYPECAST"/></module><module name="NoWhitespaceAfter"><!-- Checks that there is no whitespace after various unary operators.Linebreaks are allowed.--><property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,UNARY_PLUS"/><property name="allowLineBreaks" value="true"/><property name="severity" value="error"/></module><module name="NoWhitespaceBefore"><!-- Checks that there is no whitespace before various unary operators.Linebreaks are allowed.--><property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/><property name="allowLineBreaks" value="true"/><property name="severity" value="error"/></module><module name="OperatorWrap"><!-- Checks that operators like + and ? appear at newlines rather thanat the end of the previous line.--><property name="option" value="NL"/><property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL,GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD,NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/></module><module name="OperatorWrap"><!-- Checks that assignment operators are at the end of the line. --><property name="option" value="eol"/><property name="tokens" value="ASSIGN"/></module><module name="ParenPad"><!-- Checks that there is no whitespace before close parens or afteropen parens.--><property name="severity" value="error"/></module><module name="ModifierOrder"/></module>
</module>
suppressions.xml
在项目根目录创建文件script/checkstyle/suppressions.xml
<?xml version="1.0"?>
<!--Licensed to the Apache Software Foundation (ASF) under oneor more contributor license agreements. See the NOTICE filedistributed with this work for additional informationregarding copyright ownership. The ASF licenses this fileto you under the Apache License, Version 2.0 (the"License"); you may not use this file except in compliancewith the License. You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing,software distributed under the License is distributed on an"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANYKIND, either express or implied. See the License for thespecific language governing permissions and limitationsunder the License.-->
<!DOCTYPE suppressions PUBLIC"-//Puppy Crawl//DTD Suppressions 1.1//EN""http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"><suppressions><suppress checks="JavadocPackage" files=".*[\\/]src[\\/]test[\\/].*"/><suppress checks="JavadocPackage" files=".*[\\/]maven-archetypes[\\/].*"/><suppress checks="JavadocPackage" files=".*[\\/]examples[\\/].*"/><!-- suppress javadoc check for impl classes and package-info.java --><suppress checks="JavadocType" files=".*Impl\.java$" /><suppress checks="JavadocStyle" files=".+[\\/]package-info\.java$" /><!-- suppress all checks in the generated directories --><suppress checks=".*" files=".+[\\/]generated[\\/].+\.java"/><suppress checks=".*" files=".+[\\/]generated-sources[\\/].+\.java"/><suppress checks=".*" files=".+[\\/]generated-test-sources[\\/].+\.java"/><!-- suppress most all checks expect below--><suppress checks="^(?!.*(UnusedImports|IllegalImport)).*$" files=".*[\\/]src[\\/]test[\\/].*"/>
</suppressions>
pom.xml
<build><plugins><plugin><groupId>com.diffplug.spotless</groupId><artifactId>spotless-maven-plugin</artifactId><version>2.29.0</version><configuration><skip>false</skip><java><googleJavaFormat><version>1.7</version><style>AOSP</style></googleJavaFormat><removeUnusedImports /><formatAnnotations /><importOrder><order>wiki.hadoop,org.apache,org,com,cn,,javax,java,\#</order></importOrder><replaceRegex><name>Remove wildcard imports</name><searchRegex>import\s+(static)*\s*[^\*\s]+\*;(\r\n|\r|\n)</searchRegex><replacement>$1</replacement></replaceRegex></java><pom><sortPom><encoding>UTF-8</encoding><nrOfIndentSpace>4</nrOfIndentSpace><keepBlankLines>true</keepBlankLines><indentBlankLines>false</indentBlankLines><indentSchemaLocation>true</indentSchemaLocation><spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement><sortModules>false</sortModules><sortExecutions>false</sortExecutions><predefinedSortOrder>custom_1</predefinedSortOrder><expandEmptyElements>false</expandEmptyElements><sortProperties>false</sortProperties></sortPom><replace><name>Leading blank line</name><search>project</search><replacement>project</replacement></replace></pom><markdown><includes><include>docs/**/*.md</include></includes><flexmark /></markdown><upToDateChecking><enabled>true</enabled></upToDateChecking></configuration><executions><execution><id>spotless-check</id><goals><goal>check</goal></goals><phase>validate</phase></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-checkstyle-plugin</artifactId><version>3.3.0</version><configuration><configLocation>./script/checkstyle/checkstyle.xml</configLocation><suppressionsLocation>./script/checkstyle/suppressions.xml</suppressionsLocation><includeTestSourceDirectory>true</includeTestSourceDirectory><consoleOutput>true</consoleOutput><failsOnError>true</failsOnError><linkXRef>false</linkXRef></configuration><executions><execution><id>validate</id><phase>validate</phase><goals><goal>check</goal></goals></execution></executions></plugin></plugins></build>