Content

Overview

Checkstyle uses XPath queries in two main ways:

  • Violation suppression — via SuppressionXpathFilter and SuppressionXpathSingleFilter, which let you suppress specific violations by matching AST nodes with XPath expressions.
  • Custom checks — via the MatchXpath check, which fires a violation on every AST node matched by a given XPath query, allowing users to write custom style rules without writing Java code.

This page explains the XPath version supported, how Checkstyle's AST maps to XPath, the @text attribute, supported axes, and how to use the CLI tools to build and test XPath queries.

XPath Version

Checkstyle supports XPath 3.1 via the Saxon-HE library. For the exact Saxon-HE version bundled with your Checkstyle release, see the dependency report and the corresponding documentation at saxonica.com.

Note that XPath 2.0 and XPath 1.0 are not fully backwards compatible. For example, a numeric comparison such as "4" > "4.0" yields different results depending on the version. Always write queries with XPath 3.1 semantics in mind.

AST and XPath

Checkstyle parses each Java source file into an Abstract Syntax Tree (AST). XPath queries operate on this tree. Each node in the tree corresponds to a Java language construct and has a token type (e.g. CLASS_DEF, METHOD_DEF, IDENT).

You can print the full AST of any Java file using the -T option of the Checkstyle command line tool:


$ java -jar checkstyle-X.XX-all.jar -T Main.java
CLASS_DEF -> CLASS_DEF [1:0]
|--MODIFIERS -> MODIFIERS [1:0]
|   `--LITERAL_PUBLIC -> public [1:0]
|--LITERAL_CLASS -> class [1:7]
|--IDENT -> Main [1:13]
`--OBJBLOCK -> OBJBLOCK [1:18]
    |--LCURLY -> { [1:18]
    |--METHOD_DEF -> METHOD_DEF [2:4]
    |   |--MODIFIERS -> MODIFIERS [2:4]
    |   |   `--LITERAL_PUBLIC -> public [2:4]
    |   |--TYPE -> TYPE [2:11]
    |   |   `--IDENT -> String [2:11]
    |   |--IDENT -> sayHello [2:18]
    |   |--LPAREN -> ( [2:26]
    |   |--PARAMETERS -> PARAMETERS [2:27]
    |   |   `--PARAMETER_DEF -> PARAMETER_DEF [2:27]
    |   |       |--MODIFIERS -> MODIFIERS [2:27]
    |   |       |--TYPE -> TYPE [2:27]
    |   |       |   `--IDENT -> String [2:27]
    |   |       `--IDENT -> name [2:34]
    |   |--RPAREN -> ) [2:38]
    |   `--SLIST -> { [2:40]
    |       |--LITERAL_RETURN -> return [3:8]
    |       |   `--SEMI -> ; [3:31]
    |       `--RCURLY -> } [4:4]
    `--RCURLY -> } [5:0]
      

You can then use the -b option to test an XPath query against a file and see which AST nodes it matches:


$ java -jar checkstyle-X.XX-all.jar Main.java -b "//METHOD_DEF[./IDENT[@text='sayHello']]"
CLASS_DEF -> CLASS_DEF [1:0]
`--OBJBLOCK -> OBJBLOCK [1:18]
    |--METHOD_DEF -> METHOD_DEF [2:4]
      

Additionally, Checkstyle provides a GUI application that displays the AST interactively, making it easier to explore the tree structure and build XPath queries.

For full XPath syntax reference, see XPath Syntax. For XPath functions, see XSLT/XPath Reference.

The @text Attribute

Checkstyle extends XPath with a special @text attribute that exposes the source text of an AST node. This is available only on certain token types that carry meaningful text — for example, IDENT nodes expose the identifier name, and STRING_LITERAL nodes expose the literal value.

For the full list of token types that support @text, see XpathUtil in the Checkstyle source.

Example — match any method named foo:


//METHOD_DEF[./IDENT[@text='foo']]
      

Example — match any method named test or foo:


//METHOD_DEF[./IDENT[@text='test' or @text='foo']]
      

Supported XPath Axes

Checkstyle supports the following XPath axes when querying the AST:

  • ancestor
  • ancestor-or-self
  • attribute
  • child
  • descendant
  • descendant-or-self
  • following
  • following-sibling
  • parent
  • preceding
  • preceding-sibling
  • self

Using XPath for Suppressions

XPath-based suppression allows you to suppress violations on specific AST nodes rather than by line number or message pattern. This is more robust because it does not break when code is reformatted or lines are added.

There are two filters available:

The command line tool can automatically generate XPath suppressions for detected violations using the -g flag:


$ java -jar checkstyle-X.XX-all.jar -c config.xml -g Main.java
      

Note that XPath-based suppression does not support all checks. Checks that do not log violations against an AST node (e.g. file-level checks) cannot be suppressed this way. See SuppressionXpathFilter for the full list of incompatible checks.

Using XPath for Custom Checks

The MatchXpath check fires a violation on every AST node matched by a given XPath query. This allows users to implement custom style rules entirely in configuration, without writing any Java code.

It is recommended to always provide a custom violation message using the message element with key matchxpath.match to explain what is disallowed and what to use instead.

Example — require public methods to appear before private methods:


<module name="Checker">
  <module name="TreeWalker">
    <module name="MatchXpath">
      <property name="query"
           value="//METHOD_DEF[.//LITERAL_PRIVATE
                  and following-sibling::METHOD_DEF[.//LITERAL_PUBLIC]]"/>
      <message key="matchxpath.match"
           value="Private methods must appear after public methods"/>
    </module>
  </module>
</module>
      

Example — disallow parameterized constructors:


<module name="Checker">
  <module name="TreeWalker">
    <module name="MatchXpath">
      <property name="query"
           value="//CTOR_DEF[count(./PARAMETERS/*) > 0]"/>
      <message key="matchxpath.match"
           value="Parameterized constructors are not allowed"/>
    </module>
  </module>
</module>
      

Example — enforce use of var for new instance creation:


<module name="Checker">
  <module name="TreeWalker">
    <module name="MatchXpath">
      <property name="query"
           value="//VARIABLE_DEF[./ASSIGN/EXPR/LITERAL_NEW
                  and not(./TYPE/IDENT[@text='var'])]"/>
      <message key="matchxpath.match"
           value="New instances should be created via var keyword"/>
    </module>
  </module>
</module>
      

Example — disallow classes with more than one constructor:


<module name="Checker">
  <module name="TreeWalker">
    <module name="MatchXpath">
      <property name="query"
           value="//CLASS_DEF[count(./OBJBLOCK/CTOR_DEF) > 1]"/>
      <message key="matchxpath.match"
           value="Classes with more than 1 constructor are not allowed"/>
    </module>
  </module>
</module>
      

See the full MatchXpath examples for more patterns.