Try
https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathFilter
You can configure it as:
<module name="SuppressionXpathFilter">
<property name="file" value="suppressions-xpath.xml"/>
<property name="optional" value="false"/>
</module>
Generate Xpath suppressions using the CLI with the -g option and specify the output using the -o switch.
https://checkstyle.sourceforge.io/cmdline.html#Command_line_usage
Here's an ant snippet that will help you set up your Checkstyle suppressions auto generation; you can integrate it into Maven using the Antrun plugin.
<target name="checkstyleg">
<move file="suppressions-xpath.xml"
tofile="suppressions-xpath.xml.bak"
preservelastmodified="true"
force="true"
failonerror="false"
verbose="true"/>
<fileset dir="${basedir}"
id="javasrcs">
<include name="**/*.java" />
</fileset>
<pathconvert property="sources"
refid="javasrcs"
pathsep=" " />
<loadfile property="cs.cp"
srcFile="../${cs.classpath.file}" />
<java classname="${cs.main.class}"
logError="true">
<arg line="-c ../${cs.config} -p ${cs.properties} -o ${ant.project.name}-xpath.xml -g ${sources}" />
<classpath>
<pathelement path="${cs.cp}" />
<pathelement path="${java.class.path}" />
</classpath>
</java>
<condition property="file.is.empty" else="false">
<length file="${ant.project.name}-xpath.xml" when="equal" length="0" />
</condition>
<if>
<equals arg1="${file.is.empty}" arg2="false"/>
<then>
<move file="${ant.project.name}-xpath.xml"
tofile="suppressions-xpath.xml"
preservelastmodified="true"
force="true"
failonerror="true"
verbose="true"/>
</then>
</if>
</target>
The suppressions-xpath.xml is specified as the Xpath suppressions source in the Checkstyle rules configuration.
In the snippet above, I'm loading the Checkstyle classpath from a file cs.cp into a property. You can choose to specify the classpath directly.
Or you could use groovy within Maven (or Ant) to do the same:
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.nio.file.Paths
def backupSuppressions() {
def supprFileName =
project.properties["checkstyle.suppressionsFile"]
def suppr = Paths.get(supprFileName)
def target = null
if (Files.exists(suppr)) {
def supprBak = Paths.get(supprFileName + ".bak")
target = Files.move(suppr, supprBak,
StandardCopyOption.REPLACE_EXISTING)
println "Backed up " + supprFileName
}
return target
}
def renameSuppressions() {
def supprFileName =
project.properties["checkstyle.suppressionsFile"]
def suppr = Paths.get(project.name + "-xpath.xml")
def target = null
if (Files.exists(suppr)) {
def supprNew = Paths.get(supprFileName)
target = Files.move(suppr, supprNew)
println "Renamed " + suppr + " to " + supprFileName
}
return target
}
def getClassPath(classLoader, sb) {
classLoader.getURLs().each {url->
sb.append("${url.getFile().toString()}:")
}
if (classLoader.parent) {
getClassPath(classLoader.parent, sb)
}
return sb.toString()
}
backupSuppressions()
def cp = getClassPath(this.class.classLoader,
new StringBuilder())
def csMainClass =
project.properties["cs.main.class"]
def csRules =
project.properties["checkstyle.rules"]
def csProps =
project.properties["checkstyle.properties"]
String[] args = ["java", "-cp", cp,
csMainClass,
"-c", csRules,
"-p", csProps,
"-o", project.name + "-xpath.xml",
"-g", "src"]
ProcessBuilder pb = new ProcessBuilder(args)
pb = pb.inheritIO()
Process proc = pb.start()
proc.waitFor()
renameSuppressions()
The only drawback with using Xpath suppressions---besides the checks it doesn't support---is if you have code like the following:
package cstests;
public interface TestMagicNumber {
static byte[] getAsciiRotator() {
byte[] rotation = new byte[95 * 2];
for (byte i = ' '; i <= '~'; i++) {
rotation[i - ' '] = i;
rotation[i + 95 - ' '] = i;
}
return rotation;
}
}
The Xpath suppression generated in this case is not ingested by Checkstyle and the checker fails with an exception on the generated suppression:
<suppress-xpath
files="TestMagicNumber.java"
checks="MagicNumberCheck"
query="/INTERFACE_DEF[./IDENT[@text='TestMagicNumber']]/OBJBLOCK/METHOD_DEF[./IDENT[@text='getAsciiRotator']]/SLIST/LITERAL_FOR/SLIST/EXPR/ASSIGN[./IDENT[@text='i']]/INDEX_OP[./IDENT[@text='rotation']]/EXPR/MINUS[./CHAR_LITERAL[@text='' '']]/PLUS[./IDENT[@text='i']]/NUM_INT[@text='95']"/>
Generating Xpath suppressions is recommended when you have fixed all other violations and wish to suppress the rest. It will not allow you to select specific instances in the code to suppress. You can , however, pick and choose suppressions from the generated file to do just that.
SuppressionXpathSingleFilter is better suited to identify and suppress a specific rule, file or error message. You can configure multiple filters identifying each one by the id attribute.
https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathSingleFilter