为什么主 Spring 启动应用程序总是触发 PMD 的 HideUtilityClassConstructorCheck?

Why does the main Spring Boot application always trigger PMD's HideUtilityClassConstructorCheck?

标准 Spring 引导应用程序有一些主要方法 class 文件,比如 SampleApplication.java,看起来像这样:

@SpringBootApplication
@RestController
public class SampleApplication {

    public static void main(final String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

}

但是 PMD 静态分析将其标记为错误 (HideUtilityClassConstructorCheck):

Utility classes should not have a public or default constructor.

Makes sure that utility classes (classes that contain only static methods or fields in their API) do not have a public constructor.

Rationale: Instantiating utility classes does not make sense. Hence the constructors should either be private or (if you want to allow subclassing) protected. A common mistake is forgetting to hide the default constructor.

If you make the constructor protected you may want to consider the following constructor implementation technique to disallow instantiating subclasses:

public class StringUtils // not final to allow subclassing { protected StringUtils() { // prevents calls from subclass throw new UnsupportedOperationException(); } public static int count(char c, String s) { // ... } }

这是为什么?我应该抑制这个 PMD 错误吗?

检查不言自明。

默认情况下,任何代码检查器(IntelliJ IDEA、FindBugs、PMD、Sonar)都假定如果 class 只有 static 方法,那么它就是 utility class。实用程序 class 的示例是 java.lang.Math,它看起来像这样:

public final class Math {

    /**
     * Don't let anyone instantiate this class.
     */
    private Math() {}

    public static double exp(double a) {
        ...
    }

    // More helper methods
}

这样的 classes 被设计为将它用作一组静态函数:为它声明私有构造函数是一种很好的做法,这样就不会有人错误地实例化它并声明 class final,因为扩展它没有意义。

在你的情况下(如果 Spring 引导应用程序的几乎每个入口点)SampleApplication class 有一个 public static void main 方法,所以 PMD 决定它的效用 class,检查私有构造和最终修饰符并标记错误。这不是问题,PMD 只是不知道 Spring Boot 或任何其他框架及其入口点,因此抑制此警告并将您的 class 从 PMD 中排除是非常有意义的:对我来说它比将私有构造函数添加到应用程序入口点在语义上更正确。

使用 PMD 规则集 XML 文件中的以下代码片段,可以仅针对 类 使用 @SpringBootApplication 注释抑制 PMD UseUtilityClass 规则:

<rule ref="category/java/design.xml/UseUtilityClass">
    <properties>
        <property name="violationSuppressXPath" value="//ClassOrInterfaceDeclaration/preceding-sibling::Annotation/MarkerAnnotation/Name[@Image='SpringBootApplication']" />
    </properties>
</rule>

您可以使用 @SuppressWarnings("PMD") 抑制入口点中的警告,因为 Spring Core 使用基于反射和 PMD 分析器无法分析的其他内容的面向方面的编程。不要担心在 class

中抑制警告

例如:

@SuppressWarnings("PMD")
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
@EnableScheduling
@EnableConfigurationProperties
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

您可以在这里阅读更多内容:https://pmd.github.io/latest/pmd_userdocs_suppressing_warnings.html

现在您可以像这样忽略注释 @SpringBootApplication

<rule ref="category/java/design.xml/UseUtilityClass">
    <properties>
        <property name="ignoredAnnotations" value="org.springframework.boot.autoconfigure.SpringBootApplication"/>
    </properties>
</rule>

UseUtilityClass 因为 PMD 6.16.0 (30-June-2019)