一.CheckStyle是什么
CheckStyle 是一款帮助开发人员编写出遵守编码标准的Java代码的开发工具.它的主要任务是执行代码检查(这是一项使人觉得枯燥但是又极其重要的工作.).这使其成为执行编码标准的绝佳工具.
CheckStyle 可以检测源码中的很多问题(比如类设计问题,方法设计问题),同时它还具有检测代码布局和格式化问题的能力,如果你想了解全能CheckStyle到底能干嘛,那么这条链接可能就会你想要的.
Checkstyle 是高度可配置的,几乎支持任何的编码标准,这里提供一个示例,支持Sun Code Conventions, Google Java Style.
道理我都懂,没图说JB:
你可以在这里看到一个使用CheckStyle 和Maven生成修改建议的报告.
二.CheckStyle配置
CheckStyle使用XML来管理配置项,通过xml您可以指定哪些检测模块要运用到java源文件的代码检测中.
CheckStyle许多模块都是TreeWalker FileSetCheck模块的子模块。TreeWalker通过将每个Java源文件单独转换为抽象语法树,然后将结果传递给每个子模块,以供子模块做进一步分析.
这种情况有点类似于网络数据传输中,数据被逐层拆包解析的过程
Module
- 一个基本的配置文件被Checker模块所外包.
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
<module name="Checker">
....
</module>
2.CheckStyle是通过module的name属性标识来加载类.这个name的写法有一些讲究.
.根据包限定名称直接加载类(这种写法适用于导入第三方检测模块)
<module name="com.puppycrawl.tools.checkstyle.TreeWalker"/>
.加载一个内置类
<module name="AvoidStarImport"/>
.当内部类中名称以[Check]结尾时,可以简写,例如我要加载"com.puppycrawl.tools.checkstyle.checks.ConstantNameCheck "这个类
<module name="ConstantName"/>
Properties
你可以在 Property Types 了解更多的属性配置信息
Module的Properties属性控制Module如何执行任务,一般来说,Properties都有一个默认值,如果默认值符合您的要求,那么完全没必要去重新为它赋值.而当Properties的默认值无法满足您的要求时,您可要在Module内定义属性元素.并为其重新赋值.
<!--MethodLength模块中的max属性指定方法或者构造函数中允许的最大行数.默认值是150,您可以通过以下方式修改它的值-->
<module name="MethodLength">
<property name="max" value="60"/>
</module>
模块设置的属性可以被子模块所继承
<!--以下配置片段中,tabWidth=4会作用于TreeWalker及其子模块中-->
<module name="Checker">
<module name="JavadocPackage"/>
<module name="TreeWalker">
<property name="tabWidth" value="4"/>
<module name="AvoidStarImport"/>
<module name="ConstantName"/>
...
</module>
</module>
可以使用 ${property_name}表达式来指定module的属性值.
<module name="Header">
<property name="headerFile" value="${checkstyle.header.file}"/>
</module>
property_name 是命令行属性或ant Checkstyle任务属性,如此,您可以使用属性扩展来重新指定模块属性值,而无需更改配置文档。
property 提供了一个可选的默认属性,当该值中的属性无法解析时使用
<!--当无法获取到${checkstyle.javadoc.severity}的属性值时,severity=error-->
<module name="JavadocMethod">
<property name="severity"
value="${checkstyle.javadoc.severity}"
default="error"/>
</module>
当设置集中式配置文件(例如整个公司的一个文件)以降低配置维护成本时,此功能非常有帮助。 对默认情况下满意的项目可以直接使用该配置文件,但具有特殊需求的单个项目可以灵活调整几个设置以满足其需要,而无需复制和维护整个配置。
Checker
Checker(3.0添加) 是 CheckStyle的根目录,同样Checker也有内置属性,该属性会直接被子Module所继承.
name | 说明 | 类型 | 默认值 | 发布版本 |
---|---|---|---|---|
basedir | string | null | 3.0 | |
cacheFile | 存放已检测为文件信息,防止重复检测 | string | null | 6.16 |
localeCountry | 国家信息 | string:空字符串或大写ISO 3166 2字国家代码 | Java虚拟机的默认区域设置国家/地区 | 3.0 |
localeLanguage | 本地语言代号 | string:空字符串或小写的ISO 639代码 | Java虚拟机的默认语言环境语言 | 3.0 |
charset | 文件字符编码 | String | System property "file.encoding" | 5.0 |
fileExtensions | 文件扩展名 | String Set | null | 6.3 |
severity | 所有违规的默认严重性级别 | Severity | error | 3.1 |
haltOnException | 如果单个文件在验证期间产生任何类型的异常,是否停止Checkstyle的执行 | Boolean | true | 7.4 |
TreeWalker
name | description | type | default value | since |
---|---|---|---|---|
tabWidth | 标签字符('\ t')的展开空间数 用于需要标签宽度的消息和检查,例如LineLength | Integer | 8 | 3.0 |
fileExtensions | 文件类型扩展名来标识Java文件。 通常只有在编译之前对Java源代码进行预处理并且原始文件没有扩展名.java时,才需要设置此属性。 | String Set | java | 3.0 |
TreeWalker模块为Java源文件创建一个语法树,并在树的节点遍历期间调用其子模块(称为Checks).语法树的每个节点都有一个令牌. 在遍历期间访问节点会触发为其令牌配置的所有检查。 例如,如果MethodLength已配置为TreeWalker的子模块,则使用方法或构造函数定义令牌访问节点将触发MethodLength以检查节点代码块的行数。
一些检查,如FileLength和LineLength,直接应用于源文件,不涉及语法树的令牌。 其他Checks Module与触发检查的可配置的令牌集相关联。 例如:
<module name="MethodLength"/>
MethodLength Module默认的token集合是{METHOD_DEF, CTOR_DEF}(方法定义,或者构造函数定义),而当某个节点包含METHOD_DEF或者CTOR_DEF令牌,那么TreeWalker 就会调用MethodLength 执行检查.
您可以使用属性令牌指定检查的特定的令牌.令牌的值是表示Check的令牌的子集的列表,如下面的元素,配置Check MethodLength仅检查方法的行数:
<module name="MethodLength">
<!--不再包含构造函数-->
<property name="tokens" value="METHOD_DEF"/>
</module>
如果你要将不同的属性令牌标记应用于同一个Checks Module中,请重写Checks Module.例如下面这样操作.
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF"/>
</module>
<module name="MethodLength">
<property name="tokens" value="CTOR_DEF"/>
<property name="max" value="60"/>
</module>
以上代码片段代表检查方法的长度(无配置则默认是150行),构造方法的长度为60行.
Severity(告警级别)
每一个Checks Module都有告警级别属性,CheckStyle给予的默认属性是Error级别.你可以向下面的代码片段一样,更改它的告警级别:
<module name="Translation">
<property name="severity" value="warning"/>
</module>
将类型转换 告警级别调至warning级别.
Custom Messages(自定义消息)
从CheckStyle5.0开始,CheckStyle的Checks Module已经被定义成可自定义输出消息.这个功能在检测消息需要引用编码样式文档中的相应部分或默认消息对于开发人员来说是太难以理解的情况下非常有用.
<module name="MemberName">
<property name="format" value="^m[a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member ''{0}'' must start with a lowercase ''m'' (checked pattern ''{1}'')."/>
</module>
请注意,消息模式必须是一个有效的java.text.MessageFormat样式模式,因此请注意占位符定义外的花括号。
每个检查配置元素可以具有零个或多个消息元素。 每个检查使用一个或多个不同的消息密钥来记录违规。 如果要自定义某个消息,则需要在消息元素的key属性中指定消息密钥。
Filters(过滤器)
Checker模块具有一组过滤器子模块,用于过滤审核事件,包括Checks发出的错误消息。 过滤器可以接受或拒绝审核事件。 如果所有过滤器都接受审核事件,则Checker会报告事件。 如果任何Filter拒绝事件,则Checker不会报告事件。 有关更多信息,请访问过滤器页面。
执行前文件过滤器(什么鬼)
检查器模块具有“执行前文件过滤器”子模块,以过滤文件被该实用程序处理。 执行前文件过滤器可以按其名称接受或拒绝文件。 如果所有执行文件过滤器都接受文件,则Checker将处理并验证文件。 如果任何执行前文件过滤器拒绝文件,则Checker会跳过该文件,并且行为类似于它不存在。 有关更多信息,请访问文件过滤器页面。
AuditListeners(审核监听器)
除了文本或XML输出的审核记录之外,Checker还可以拥有处理审核事件的自定义AuditListener。 为了使用自定义侦听器,为侦听器及其属性添加一个Checker子模块。 例如,要配置Checker,以便它使用自定义侦听器VerboseListener将审核消息打印到名为“audit.txt”的文件中,请在配置文件中包含以下模块:
<module name="com.mycompany.listeners.VerboseListener">
<property name="file" value="audit.txt"/>
</module>
Packages
Checkstyle根据模块元素的名称加载模块类,并在搜索可加载类时自动将预先指定的包前缀附加到该名称。 默认情况下,Checkstyle应用包com.puppycrawl.tools.checkstyle,com.puppycrawl.tools.checkstyle.filters和com.puppycrawl.tools.checkstyle.checks以及com.puppycrawl.tools.checkstyle的任何子包。
要指定要应用的其他包,请创建名为checkstyle_packages.xml的XML文件,并将该文件提供到包含您的自定义检查的.jar的根目录中。
请注意,通过命令行选项或Ant Checkstyle任务的属性提供包命名XML文档的支持已经在Checkstyle 5.0版本上删除。
包名称XML文档指定包名称列表。 以下是软件包名称XML文档的示例程序包com.puppycrawl.tools.checkstyle和com.puppycrawl.tools.checkstyle.checks:
<checkstyle-packages>
<package name="com.puppycrawl.tools.checkstyle">
<package name="checks"/>
</package>
</checkstyle-packages>
例如,要让Checkstyle能够使用包com.mycompany.checks中的模块,请创建下面的XML文件,并将该文件放入包含自定义检查模块的jar文件的根目录下。 该XML文件必须完全命名为checkstyle_packages.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE checkstyle-packages PUBLIC
"-//Puppy Crawl//DTD Package Names 1.0//EN"
"http://checkstyle.sourceforge.net/dtds/packages_1_0.dtd">
<checkstyle-packages>
<package name="com.mycompany.checks"/>
</checkstyle-packages>
现在你可以在配置文件中配置一个包com.mycompany.checks的模块,比如说com.mycompany.checks.MethodLimitCheck,它有一个简化的写法:
<module name="MethodLimit"/>
XML Structure(CheckStyle 的xml语法结构)
配置XML文档的以下DTD指定模块及其属性的层次结构:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT module (module|property)*>
<!ATTLIST module name NMTOKEN #REQUIRED>
<!ELEMENT property EMPTY>
<!ATTLIST property
name NMTOKEN #REQUIRED
value CDATA #REQUIRED
>
Checkstyle在加载文档时验证配置XML文档。 要根据上述配置DTD进行验证,请在配置XML文档中包含以下文档类型声明:
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
Checkstyle还严格执行XML声明的编码属性。 如果Checkstyle拒绝配置文档的编码,请更正encoding属性的值,或者完全删除编码属性。
有关配置XML文档的完整示例,请检查检查Sun编码约定的文档docs / sun_checks.xml。
这是一个包名称XML文档的DTD:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT checkstyle-packages (package)*>
<!ELEMENT package (package)*>
<!ATTLIST package name NMTOKEN #REQUIRED>
Checkstyle还会在加载文档时验证包名XML文档。 要根据上述软件包名称DTD进行验证,请在软件包名称XML文档中包含以下文档类型声明:
<!DOCTYPE checkstyle-packages PUBLIC
"-//Puppy Crawl//DTD Package Names 1.1//EN"
"http://checkstyle.sourceforge.net/dtds/packages_1_1.dtd">
这是一个抑制XML文档的DTD:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT suppressions (suppress*)>
<!ELEMENT suppress EMPTY>
<!ATTLIST suppress files CDATA #REQUIRED
checks CDATA #IMPLIED
id CDATA #IMPLIED
lines CDATA #IMPLIED
columns CDATA #IMPLIED>
您可要在这里找到所有支持的Check Module类型.
========================================================================
Demo展示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<!--Create by fengwenhua 2017年11月2日13:32:57-->
<!--这是CheckStyle根目录-->
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="warning"/>
<!--该节点可以把Java源文件的内容解析成语法树,并将语法树内容分发给子Module进行进一步的检测-->
<module name="TreeWalker">
<!--检查[标识符名称]中的缩写(连续大写字母)的长度,它也允许强制骆驼命名。(需要父Module TreeWalker 支持)-->
<module name="AbbreviationAsWordInName">
<!--当变量定义或类定义时,该检测有效-->
<property name="tokens" value="VARIABLE_DEF,CLASS_DEF"/>
<!--一般来说,静态常量都是大写 忽略该检测-->
<property name="ignoreStatic" value="true"/>
<!--最多可以连续打印1个大写字母,MyTest正确,MyTEst错误-->
<property name="allowedAbbreviationLength" value="0"/>
<!--必须跳过检查的缩写列表。缩写列表应该用逗号隔开,不允许有空格。-->
<property name="allowedAbbreviations" value="XML,URL"/>
</module>
<!--验证抽象类的标识符-->
<module name="AbstractClassName">
<!--抽象类以Abstract开头-->
<property name="format" value="^Abstract.+$"/>
<!--匹配名称的类的抽象修饰符丢失是否需要告警:默认就是false,因此可以不写-->
<property name="ignoreModifier" value="false"/>
</module>
<!--匿名内部类最大长度值:太过庞大的匿名内部类在后期维护会相当困难,因此需要保证让其短小精悍-->
<module name="AnonInnerLength">
<property name="max" value="100"/>
</module>
<!--数组定义风格:C风格(String args[])还会Java风格(String[] args)-->
<module name="ArrayTypeStyle">
<property name="javaStyle" value="true"/>
</module>
<!--
内联条件很难阅读,所以使用编码标准禁止它(比如三目运算符)
<module name="AvoidInlineConditionals"/>
-->
<!--是否允许*号导包-->
<module name="AvoidStarImport">
<!--被允许*号导包-->
<property name="excludes" value="java.io,java.net,java.lang.Math"/>
<!--是否可以import java.util.*; 这样导包-->
<property name="allowClassImports" value="false"/>
<!--是否可以import static org.junit.Assert.*;静态导包-->
<property name="allowStaticMemberImports" value="true"/>
</module>
<!--检测无效导包-->
<module name="UnusedImports"/>
<!--检测是否有不必要的括号-->
<module name="UnnecessaryParentheses"/>
<!--接口名称定义,以I开头-->
<module name="TypeName">
<property name="format" value="^I_[a-zA-Z0-9]*$"/>
<property name="tokens" value="INTERFACE_DEF"/>
</module>
<!--检测TODO-->
<module name="TodoComment">
<property name="format" value="TODO"/>
</module>
</module>
</module>
参考链接:
CheckStyle官网