SuppressionXpathFilter
Since Checkstyle 8.6
Description
SuppressionXpathFilter works as SuppressionFilter, but also processes suppress-xpath elements, which contain xpath-expressions. Xpath-expressions are queries for suppressed nodes inside the AST tree. Currently, filter does not support the following checks:
- NoCodeInFile (reason is that AST is not generated for a file not containing code)
- Regexp (reason is at #7759)
- RegexpSinglelineJava (reason is at #7759)
Also, the filter does not support suppressions inside javadoc reported by Javadoc checks:
- AtclauseOrder
- JavadocBlockTagLocation
- JavadocMethod
- JavadocMissingLeadingAsterisk
- JavadocMissingWhitespaceAfterAsterisk
- JavadocParagraph
- JavadocStyle
- JavadocTagContinuationIndentation
- JavadocType
- MissingDeprecated
- NonEmptyAtclauseDescription
- RequireEmptyLineBeforeBlockTagGroup
- SingleLineJavadoc
- SummaryJavadoc
- WriteTag
Note, that support for these Checks will be available after resolving issue #5770.
Currently, filter supports the following xpath axes:
- ancestor
- ancestor-or-self
- attribute
- child
- descendant
- descendant-or-self
- following
- following-sibling
- parent
- preceding
- preceding-sibling
- self
You can use the command line helper tool to generate xpath suppressions based on your configuration file and input files. See here for more details.
Checkstyle supports XPath 3.1 or higher, for exact version please find "Saxon-HE" version in our dependency report and find related documentation at saxonica.com.
Notes
The suppression file location is checked in following order:
- as a filesystem location
-
if no file found, and the location starts with either
http://orhttps://, then it is interpreted as a URL -
if no file found, then passed to the
ClassLoader.getResource()method.
SuppressionXpathFilter can suppress Checks that have Treewalker as parent module.
A suppressions XML document contains a set of suppress and suppress-xpath elements, where each suppress-xpath element can have the following attributes:
-
files- a Pattern matched against the file name associated with an audit event. It is optional. -
checks- a Pattern matched against the name of the check associated with an audit event. Optional as long asidormessageis specified. -
message- a Pattern matched against the message of the check associated with an audit event. Optional as long aschecksoridis specified. -
id- a String matched against the ID of the check associated with an audit event. Optional as long aschecksormessageis specified. -
query- a String xpath query. It is optional.
Each audit event is checked against each suppress and suppress-xpath element. It is suppressed if all specified attributes match against the audit event.
ATTENTION: filtering by message is dependent on runtime locale. If project is running in different languages it is better to avoid filtering by message.
Attention: The structure of the Abstract Syntax Tree (AST) can change depending on the enabled checks. If "comment-aware" checks (such as TodoComment) are enabled, comment nodes are added to the AST. XPath queries should be written robustly to handle the potential presence of comment nodes. For example, relying on strict count(*) checks might fail if comments are present in the code block.
Properties
| name | description | type | default value | since |
|---|---|---|---|---|
| file | Specify the location of the suppressions XML document file. | String | null |
8.6 |
| optional | Control what to do when the file is not existing. If optional is set to false the file must exist, or else it ends with error. On the other hand if optional is true and file is not found, the filter accepts all audit events. | boolean | false |
8.6 |
Examples
For example #0, the following configuration example directs the Checker to use a SuppressionXpathFilter with suppressions file config/suppressions0.xml and optional property set to false:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions0.xml"/>
<property name="optional" value="false"/>
</module>
<module name="CyclomaticComplexity">
<property name="max" value="3"/>
</module>
</module>
</module>
The following suppressions XML document directs a SuppressionXpathFilter to reject CyclomaticComplexity violations for all methods with name sayHelloWorld inside Example0 and Test files. The optional property is set to false, which means the suppressions file must exist, otherwise checkstyle ends with error.
Currently, xpath queries support one type of attribute @text. @text - addresses to the text value of the node. For example: variable name, annotation name, text content, etc. Only the following token types support @text attribute: TokenTypes.IDENT, TokenTypes.STRING_LITERAL, TokenTypes.CHAR_LITERAL, TokenTypes.NUM_LONG, TokenTypes.NUM_INT, TokenTypes.NUM_DOUBLE, TokenTypes.NUM_FLOAT. These token types were selected because only their text values are different in content from token type and represent text value from file and can be used in xpath queries for more accurate results. Other token types always have constant values.
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="CyclomaticComplexity"
files="Example0.java|Test.java"
query="//METHOD_DEF[./IDENT[@text='sayHelloWorld']]"/>
</suppressions>
Results:
public class Example0 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() { // filtered violation 'Cyclomatic Complexity is 4'
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #1, the following configuration demonstrates the optional property. The file property points to a non-existent suppressions file and optional is set to true, so suppressions are skipped and violations are reported:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/non-existent-suppressions.xml"/>
<property name="optional" value="true"/>
</module>
<module name="CyclomaticComplexity">
<property name="max" value="3"/>
</module>
</module>
</module>
Results:
public class Example1 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() { // violation 'Cyclomatic Complexity is 4'
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #2, To configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions2.xml"/>
</module>
<module name="EmptyLineSeparator"/>
</module>
</module>
In order to suppress checks for package definitions:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks=".*" query="/COMPILATION_UNIT/PACKAGE_DEF"/>
</suppressions>
Results:
// violation 3 lines below "'VARIABLE_DEF' should be separated from previous line"
public class Example2 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {} // violation 'should be separated from previous line'
public void DoMATH() {} // violation 'should be separated from previous line'
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #3, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions3.xml"/>
</module>
<module name="LeftCurly">
<property name="option" value="nl"/>
</module>
</module>
</module>
In order to suppress checks for parent element of the first-ever variable definition:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks=".*" query="descendant::VARIABLE_DEF[1]/.."/>
</suppressions>
Results:
// filtered violation below "'{' at column 23 should be on a new line."
public class Example3 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
// violation below, "'{' at column 36 should be on a new line."
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
// violation below, "'{' at column 27 should be on a new line."
public void changeAge() {
age = 24;
}
// violation below, "'{' at column 28 should be on a new line."
public void testMethod() {
int TestVariable;
int WeirdName;
}
// violation below, "'{' at column 31 should be on a new line."
public void sayHelloWorld() {// violation below, 'should be on a new line."
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
} // violation below, "'{' at column 23 should be on a new line."
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #4, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions4.xml"/>
</module>
<module name="EmptyLineSeparator"/>
</module>
</module>
In order to suppress checks for elements which are either class definitions, or method definitions.
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks=".*" query="//CLASS_DEF | //METHOD_DEF"/>
</suppressions>
Results:
// violation 3 lines below "'VARIABLE_DEF' should be separated from previous line"
public class Example4 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {} // filtered violation 'separated from previous line'
public void DoMATH() {} // filtered violation 'separated from previous line'
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #5, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions5.xml"/>
</module>
<module name="MethodName"/>
</module>
</module>
In order to suppress checks for certain methods:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks=".*" query="//METHOD_DEF/IDENT[@text='GetSomeVar' or @text='SetSomeVar']"/>
</suppressions>
Results:
// filtered violation 4 lines below "Name 'SetSomeVar' must match pattern"
public class Example5 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {} // violation, "Name 'DoMATH' must match pattern"
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {} // violation, "Name 'Test1' must match pattern"
@Generated("second")
public void Test2() {} // violation, "Name 'Test2' must match pattern"
}
For example #6, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions6.xml"/>
</module>
<module name="LocalVariableName"/>
</module>
</module>
In order to suppress checks for variable TestVariable inside testMethod method inside Example6 class.
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks=".*" query="//CLASS_DEF[./IDENT[@text='Example6']]
//METHOD_DEF[./IDENT[@text='testMethod']]
//VARIABLE_DEF/IDENT[@text='TestVariable']"/>
</suppressions>
Results:
public class Example6 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable; // filtered violation 'Name 'TestVariable' must match pattern'
int WeirdName; // violation, "Name 'WeirdName' must match pattern"
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #7, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions7.xml"/>
</module>
<module name="MagicNumber"/>
<module name="MethodName"/>
</module>
</module>
In the following sample, violations for MethodName check will be suppressed for classes with name Main or for methods with name DoMATH:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="MethodName" query="//CLASS_DEF[./IDENT[@text='Main']]//*
| //METHOD_DEF[./IDENT[@text='DoMATH']]/*"/>
</suppressions>
Results:
public class Example7 {
int age = 23; // violation, "'23' is a magic number."
private int wordCount = 11; // violation, "'11' is a magic number."
public void SetSomeVar() {} // violation "Name 'SetSomeVar' must match pattern"
public void DoMATH() {} // filtered violation "Name 'DoMATH' must match pattern"
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24; // violation, "'24' is a magic number."
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {} // violation, "Name 'Test1' must match pattern"
@Generated("second")
public void Test2() {} // violation, "Name 'Test2' must match pattern"
}
For example #8, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions8.xml"/>
</module>
<module name="RequireThis">
<property name="validateOnlyOverlapping" value="false"/>
</module>
</module>
</module>
In order to suppress RequireThis violations for variable age inside changeAge method.
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="RequireThis"
query="//CLASS_DEF[./IDENT[@text='Example8']]
//METHOD_DEF[./IDENT[@text='changeAge']]//ASSIGN/IDENT[@text='age']"/>
</suppressions>
Results:
public class Example8 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24; // filtered violation 'Reference to instance variable'
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() { // violation below 'Reference to instance variable'
if (age > 0 && wordCount > 0) { // violation 'Reference to instance variable'
System.out.println("Hello");
}
else if (age < 0) { // violation 'Reference to instance variable'
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example 9, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions9.xml"/>
</module>
<module name="IllegalThrows"/>
</module>
</module>
In order to suppress IllegalThrows violations only for methods with name throwsMethod and only for RuntimeException exceptions:
(Double colon is used for axis iterations. In the following example ancestor axis is used to iterate all ancestor nodes of the current node with type METHOD_DEF and name throwsMethod. Please read more about xpath axes at W3Schools Xpath Axes.)
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="IllegalThrows" query="//LITERAL_THROWS
/IDENT[@text='RuntimeException' and
./ancestor::METHOD_DEF[./IDENT[@text='throwsMethod']]]"/>
</suppressions>
Results:
public class Example9 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
// filtered violation below "Throwing 'RuntimeException' is not allowed."
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
For example #10, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions10.xml"/>
</module>
<module name="ModifierOrder"/>
</module>
</module>
The following sample demonstrates how to suppress all violations for method itself and all descendants. descendant-or-self axis iterates through current node and all children nodes at any level. Keyword node() selects node elements. Please read more about xpath syntax at W3Schools Xpath Syntax.
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks=".*" query="//METHOD_DEF[./IDENT[@text='legacyMethod']]
/descendant-or-self::node()"/>
</suppressions>
Results:
public class Example10 {
int age = 23;
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() { // filtered violation 'modifier out of order'
strictfp abstract class Legacy {} // filtered violation 'modifier out of order'
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
Some elements can be suppressed in different ways. For example, to suppress violation on variable wordCount in following code:
public class InputTest {
private int wordCount = 11;
}
You need to look at AST of such code by our CLI tool:
$ java -jar checkstyle-X.XX-all.jar -t InputTest.java
CLASS_DEF -> CLASS_DEF [1:0]
|--MODIFIERS -> MODIFIERS [1:0]
| `--LITERAL_PUBLIC -> public [1:0]
|--LITERAL_CLASS -> class [1:7]
|--IDENT -> InputTest [1:13]
`--OBJBLOCK -> OBJBLOCK [1:23]
|--LCURLY -> { [1:23]
|--VARIABLE_DEF -> VARIABLE_DEF [2:4]
| |--MODIFIERS -> MODIFIERS [2:4]
| | `--LITERAL_PRIVATE -> private [2:4]
| |--TYPE -> TYPE [2:12]
| | `--LITERAL_INT -> int [2:12]
| |--IDENT -> wordCount [2:16]
| |--ASSIGN -> = [2:26]
| | `--EXPR -> EXPR [2:28]
| | `--NUM_INT -> 11 [2:28]
| `--SEMI -> ; [2:30]
`--RCURLY -> } [3:0]
For example #11, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions11.xml"/>
</module>
<module name="MagicNumber"/>
</module>
</module>
The easiest way is to suppress by variable name. As you can see VARIABLE_DEF node refers to variable declaration statement and has child node with token type IDENT which is used for storing class, method, variable names.
The following example demonstrates how variable can be queried by its name:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="." query="//VARIABLE_DEF[
./IDENT[@text='wordCount']]//*"/>
</suppressions>
Results:
public class Example11 {
int age = 23; // violation "'23' is a magic number."
private int wordCount = 11; // filtered violation "'11' is a magic number."
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24; // violation "'24' is a magic number."
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
Another way is to suppress by variable value.
For example #12, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions12.xml"/>
</module>
<module name="MagicNumber"/>
</module>
</module>
Again, if you look at the printed AST tree above, you will notice that one of the grandchildren of VARIABLE_DEF node is responsible for storing variable value - NUM_INT with value 11.
The following example demonstrates how variable can be queried by its value, same approach applies to String, char, float, double, int, long data types:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="." query="//VARIABLE_DEF//NUM_INT[@text=11]"/>
</suppressions>
Results:
public class Example12 {
int age = 23; // violation "'23' is a magic number."
private int wordCount = 11; // filtered violation "'11' is a magic number."
public void SetSomeVar() {}
public void DoMATH() {}
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24; // violation "'24' is a magic number."
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
@Generated("first")
public void Test1() {}
@Generated("second")
public void Test2() {}
}
Next example is about suppressing method with certain annotation by its name and element value.
public class InputTest {
@Generated("first") // should not be suppressed
public void Test1() {}
@Generated("second") // should be suppressed
public void Test2() {}
}
First of all we need to look at AST tree printed by our CLI tool:
$ java -jar checkstyle-X.XX-all.jar -t InputTest.java
CLASS_DEF -> CLASS_DEF [1:0]
|--MODIFIERS -> MODIFIERS [1:0]
| `--LITERAL_PUBLIC -> public [1:0]
|--LITERAL_CLASS -> class [1:7]
|--IDENT -> InputTest [1:13]
`--OBJBLOCK -> OBJBLOCK [1:23]
|--LCURLY -> { [1:23]
|--METHOD_DEF -> METHOD_DEF [2:4]
| |--MODIFIERS -> MODIFIERS [2:4]
| | |--ANNOTATION -> ANNOTATION [2:4]
| | | |--AT -> @ [2:4]
| | | |--IDENT -> Generated [2:5]
| | | |--LPAREN -> ( [2:14]
| | | |--EXPR -> EXPR [2:15]
| | | | `--STRING_LITERAL -> "first" [2:15]
| | | `--RPAREN -> ) [2:22]
| | `--LITERAL_PUBLIC -> public [3:4]
| |--TYPE -> TYPE [3:11]
| | `--LITERAL_VOID -> void [3:11]
| |--IDENT -> test1 [3:16]
| |--LPAREN -> ( [3:21]
| |--PARAMETERS -> PARAMETERS [3:22]
| |--RPAREN -> ) [3:22]
| `--SLIST -> { [3:24]
| `--RCURLY -> } [4:4]
|--METHOD_DEF -> METHOD_DEF [6:4]
| |--MODIFIERS -> MODIFIERS [6:4]
| | |--ANNOTATION -> ANNOTATION [6:4]
| | | |--AT -> @ [6:4]
| | | |--IDENT -> Generated [6:5]
| | | |--LPAREN -> ( [6:14]
| | | |--EXPR -> EXPR [6:15]
| | | | `--STRING_LITERAL -> "second" [6:15]
| | | `--RPAREN -> ) [6:23]
| | `--LITERAL_PUBLIC -> public [7:4]
| |--TYPE -> TYPE [7:11]
| | `--LITERAL_VOID -> void [7:11]
| |--IDENT -> test2 [7:16]
| |--LPAREN -> ( [7:21]
| |--PARAMETERS -> PARAMETERS [7:22]
| |--RPAREN -> ) [7:22]
| `--SLIST -> { [7:24]
| `--RCURLY -> } [8:4]
`--RCURLY -> } [9:0]
For example #13, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions13.xml"/>
</module>
<module name="MethodName"/>
</module>
</module>
AST node ANNOTATION -> ANNOTATION [6:4] has direct child IDENT -> Generated [6:5], therefore can be queried by IDENT value:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="." query="//METHOD_DEF[
.//ANNOTATION/IDENT[@text='Generated']]//*"/>
</suppressions>
Results:
public class Example13 {
int age = 23; // violation 2 lines below "Name 'SetSomeVar' must match pattern"
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
// violation above, "Name 'DoMATH' must match pattern"
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
// filtered violation 2 lines below "Name 'Test1' must match pattern"
@Generated("first")
public void Test1() {}
// filtered violation 2 lines below "Name 'Test2' must match pattern"
@Generated("second")
public void Test2() {}
}
The problem with query above that it will suppress violations for all methods with annotation @Generated.
For next example #14, to configure the check:
<module name="Checker">
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config.folder}/suppressions14.xml"/>
</module>
<module name="MethodName"/>
</module>
</module>
In order to suppress methods with @Generated("second") annotations only, you need to look at AST tree again. Value of the ANNOTATION node is stored inside sub-node with token type STRING_LITERAL.
Use the following query to suppress methods with @Generated("second") annotation:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath.dtd">
<suppressions>
<suppress-xpath checks="." query="//METHOD_DEF[.//ANNOTATION[
./IDENT[@text='Generated'] and ./EXPR/STRING_LITERAL[@text='second']]]//*"/>
</suppressions>
Results:
public class Example14 {
int age = 23; // violation 2 lines below "Name 'SetSomeVar' must match pattern"
private int wordCount = 11;
public void SetSomeVar() {}
public void DoMATH() {}
// violation above "Name 'DoMATH' must match pattern"
public void throwsMethod() throws RuntimeException {}
final public void legacyMethod() {
strictfp abstract class Legacy {}
}
public void changeAge() {
age = 24;
}
public void testMethod() {
int TestVariable;
int WeirdName;
}
public void sayHelloWorld() {
if (age > 0 && wordCount > 0) {
System.out.println("Hello");
}
else if (age < 0) {
System.out.println("World");
}
}
// violation 2 lines below "Name 'Test1' must match pattern"
@Generated("first")
public void Test1() {}
// filtered violation 2 lines below "Name 'Test2' must match pattern"
@Generated("second")
public void Test2() {}
}
Example of Usage
Fully Qualified Name
com.puppycrawl.tools.checkstyle.filters.SuppressionXpathFilter
This is the fully qualified class name of the module. Use this name in configuration when an exact class reference is required.






