我在我的项目中配置了一个Checkstyle验证规则,禁止定义具有超过3个输入参数的类方法。该规则适用于我的类,但有时我必须扩展第三方类,这些类不遵守这一特定规则。

是否有可能指示Checkstyle,某个方法应该被无声地忽略?

顺便说一句,我最终得到了我自己的Checkstyle包装器:qulice.com(参见Java代码质量的严格控制)


当前回答

试一试 https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathFilter

你可以这样配置:


<module name="SuppressionXpathFilter">
  <property name="file" value="suppressions-xpath.xml"/>
  <property name="optional" value="false"/>
</module>
        

使用CLI和-g选项生成Xpath抑制,并使用-o开关指定输出。

https://checkstyle.sourceforge.io/cmdline.html#Command_line_usage

下面是一个蚂蚁代码片段,它将帮助您设置Checkstyle抑制自动生成;你可以使用Antrun插件将它集成到Maven中。


<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>

在Checkstyle规则配置中,suppress - Xpath .xml被指定为Xpath抑制源。 在上面的代码片段中,我从文件cs中加载Checkstyle类路径。Cp变成了一个属性。您可以选择直接指定类路径。

或者你可以在Maven(或Ant)中使用groovy来做同样的事情:


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()

使用Xpath抑制的唯一缺点——除了它不支持的检查——是如果你有如下代码:

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;
  }
}

在这种情况下生成的Xpath抑制没有被Checkstyle摄取,检查器在生成的抑制上出现异常而失败:

<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']"/>

当您已经修复了所有其他违规并希望抑制其余违规时,建议生成Xpath抑制。它不允许您在代码中选择要抑制的特定实例。但是,您可以从生成的文件中选择抑制来实现这一点。

SuppressionXpathSingleFilter更适合于识别和抑制特定的规则、文件或错误消息。您可以配置多个过滤器,通过id属性标识每个过滤器。

https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathSingleFilter

其他回答

如果你从qulice mvn插件(https://github.com/teamed/qulice)使用checkstyle,你可以使用以下抑制:

// @checkstyle <Rulename> (N lines)
... code with violation(s)

or


/**
 * ...
 * @checkstyle <Rulename> (N lines)
 * ...
 */
 ... code with violation(s)

同样工作良好的还有SuppressWithNearbyCommentFilter,它使用单个注释来抑制审计事件。

例如

// CHECKSTYLE IGNORE check FOR NEXT 1 LINES
public void onClick(View view) { ... }

配置一个过滤器,使CHECKSTYLE IGNORE check FOR NEXT var LINES避免触发对当前行和下一个var行(总共var+1行)的给定检查的任何审计:

<module name="SuppressWithNearbyCommentFilter">
    <property name="commentFormat" value="CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINES"/>
    <property name="checkFormat" value="$1"/>
    <property name="influenceFormat" value="$2"/>
</module>

http://checkstyle.sourceforge.net/config.html

你也可以用这些特殊的注释来包围你想要禁用特定警告的代码:

// CHECKSTYLE:DISABLE:<CheckName>
<Your code goes here>
// CHECKSTYLE:ENABLE:<CheckName>

例:// CHECKSTYLE:DISABLE:ParameterNumberCheck

您可以在这里找到支持检查的完整列表(参见直接已知子类)。

我在回答上面的问题时遇到了困难,可能是因为我将checkStyle警告设置为错误。什么工作是SuppressionFilter: http://checkstyle.sourceforge.net/config_filters.html#SuppressionFilter

这样做的缺点是行范围存储在单独的suppression .xml文件中,因此不熟悉的开发人员可能不会立即建立连接。

试一试 https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathFilter

你可以这样配置:


<module name="SuppressionXpathFilter">
  <property name="file" value="suppressions-xpath.xml"/>
  <property name="optional" value="false"/>
</module>
        

使用CLI和-g选项生成Xpath抑制,并使用-o开关指定输出。

https://checkstyle.sourceforge.io/cmdline.html#Command_line_usage

下面是一个蚂蚁代码片段,它将帮助您设置Checkstyle抑制自动生成;你可以使用Antrun插件将它集成到Maven中。


<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>

在Checkstyle规则配置中,suppress - Xpath .xml被指定为Xpath抑制源。 在上面的代码片段中,我从文件cs中加载Checkstyle类路径。Cp变成了一个属性。您可以选择直接指定类路径。

或者你可以在Maven(或Ant)中使用groovy来做同样的事情:


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()

使用Xpath抑制的唯一缺点——除了它不支持的检查——是如果你有如下代码:

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;
  }
}

在这种情况下生成的Xpath抑制没有被Checkstyle摄取,检查器在生成的抑制上出现异常而失败:

<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']"/>

当您已经修复了所有其他违规并希望抑制其余违规时,建议生成Xpath抑制。它不允许您在代码中选择要抑制的特定实例。但是,您可以从生成的文件中选择抑制来实现这一点。

SuppressionXpathSingleFilter更适合于识别和抑制特定的规则、文件或错误消息。您可以配置多个过滤器,通过id属性标识每个过滤器。

https://checkstyle.sourceforge.io/config_filters.html#SuppressionXpathSingleFilter