Почему основное приложение Spring Boot всегда запускает функцию HideUtilityClassConstructorCheck в PMD?

Стандартное приложение Spring Boot имеет некоторый основной файл класса метода, скажем SampleApplication.javaэто выглядит так:

@SpringBootApplication
@RestController
public class SampleApplication {

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

}

Но статический анализ PMD помечает это как ошибку (HideUtilityClassConstructorCheck):

У служебных классов не должно быть открытого конструктора или конструктора по умолчанию.

Обеспечивает, чтобы вспомогательные классы (классы, которые содержат только статические методы или поля в их API) не имели открытого конструктора.

Обоснование: создание служебных классов не имеет смысла. Следовательно, конструкторы должны быть либо частными, либо (если вы хотите разрешить создание подклассов) защищенными. Распространенная ошибка - забыть скрыть конструктор по умолчанию.

Если вы сделаете конструктор защищенным, вы можете рассмотреть следующую технику реализации конструктора, чтобы запретить создание экземпляров подклассов:

открытый класс StringUtils // не является окончательным, чтобы разрешить создание подклассов { protected StringUtils() { // предотвращает вызовы из подкласса throw new UnsupportedOperationException(); } public static int count(char c, String s) { // ... } }

Почему это? Должен ли я подавлять эту ошибку PMD?

2 ответа

Решение

Инспекция говорит сама за себя.

По умолчанию любой инспектор кода (IntelliJ IDEA, FindBugs, PMD, Sonar) предполагает, что если класс имеет только static методы, то это служебный класс. Примером служебного класса является 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
}

Такие классы предназначены для использования его в качестве пакета статических функций: рекомендуется объявлять для него закрытый конструктор, поэтому никто никогда не создаст его экземпляр по ошибке и не объявит класс finalпотому что расширять это не имеет смысла.

В вашем случае (и в случае почти всех точек входа приложений Spring Boot) SampleApplication у класса есть один public static void main метод, поэтому PMD решает свой служебный класс, проверяет частную конструкцию и модификатор final и отмечает ошибку. Это не проблема, PMD просто не знает о Spring Boot или каких-либо других фреймворках и их точках входа, поэтому имеет смысл отключить это предупреждение и исключить ваш класс из PMD: для меня это более семантически правильно, чем добавление частного конструктора в точка входа в приложение.

Правило PMD UseUtilityClass может быть подавлено только для классов с @SpringBootApplication аннотации с использованием следующего фрагмента в XML-файле набора правил PMD:

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

Теперь вы можете просто игнорировать аннотацию @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 июня 2019 г.)

Вы можете подавить предупреждения в своей точке входа, используя @SuppressWarnings("PMD"), потому что Spring Core использует аспектно-ориентированное программирование, основанное на отражениях и других вещах, которые анализатор PMD не может анализировать. Не беспокойтесь о подавлении предупреждений в этом классе

Для eaxmple:

@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

Другие вопросы по тегам